Merged.
authorStefan Ring <stefan@complang.tuwien.ac.at>
Wed, 22 Oct 2008 12:39:26 +0000 (14:39 +0200)
committerStefan Ring <stefan@complang.tuwien.ac.at>
Wed, 22 Oct 2008 12:39:26 +0000 (14:39 +0200)
180 files changed:
INSTALL
configure.ac
m4/jitcache.m4 [new file with mode: 0644]
src/mm/boehm-gc/include/private/gcconfig.h
src/mm/cacao-gc/final.c
src/mm/cacao-gc/final.h
src/mm/cacao-gc/gc.c
src/mm/cacao-gc/mark.c
src/mm/cacao-gc/rootset.h
src/mm/gc-boehm.cpp
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_VMField.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/native/vm/sun_misc_Unsafe.cpp
src/threads/lock.cpp
src/threads/thread.cpp
src/toolbox/logging.h
src/vm/Makefile.am
src/vm/access.c [deleted file]
src/vm/access.cpp [new file with mode: 0644]
src/vm/access.h [deleted file]
src/vm/access.hpp [new file with mode: 0644]
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.c [deleted file]
src/vm/descriptor.cpp [new file with mode: 0644]
src/vm/descriptor.h [deleted file]
src/vm/descriptor.hpp [new file with mode: 0644]
src/vm/exceptions.cpp
src/vm/exceptions.hpp
src/vm/field.cpp
src/vm/field.hpp
src/vm/finalizer.c [deleted file]
src/vm/finalizer.cpp [new file with mode: 0644]
src/vm/finalizer.h [deleted file]
src/vm/finalizer.hpp [new file with mode: 0644]
src/vm/javaobjects.cpp
src/vm/javaobjects.hpp
src/vm/jit/Makefile.am
src/vm/jit/allocator/liveness.c
src/vm/jit/allocator/simplereg.c
src/vm/jit/allocator/simplereg.h
src/vm/jit/alpha/codegen.c
src/vm/jit/alpha/md-abi.c
src/vm/jit/argument.cpp
src/vm/jit/argument.hpp
src/vm/jit/arm/codegen.c
src/vm/jit/arm/md-abi.c
src/vm/jit/builtin.cpp
src/vm/jit/builtin.hpp
src/vm/jit/code.hpp
src/vm/jit/codegen-common.cpp
src/vm/jit/codegen-common.hpp
src/vm/jit/emit-common.cpp
src/vm/jit/emit-common.hpp
src/vm/jit/executionstate.c
src/vm/jit/i386/codegen.c
src/vm/jit/i386/md-abi.c
src/vm/jit/inline/Makefile.am
src/vm/jit/inline/inline.c [deleted file]
src/vm/jit/inline/inline.cpp [new file with mode: 0644]
src/vm/jit/inline/inline.h [deleted file]
src/vm/jit/inline/inline.hpp [new file with mode: 0644]
src/vm/jit/intrp/Makefile.am
src/vm/jit/intrp/asmpart.c
src/vm/jit/intrp/codegen.c
src/vm/jit/intrp/disass.c [deleted file]
src/vm/jit/intrp/disass.cpp [new file with mode: 0644]
src/vm/jit/intrp/intrp.h
src/vm/jit/ir/instruction.cpp
src/vm/jit/ir/instruction.hpp
src/vm/jit/jit.cpp
src/vm/jit/jit.hpp
src/vm/jit/linenumbertable.hpp
src/vm/jit/loop/graph.h
src/vm/jit/loop/loop.h
src/vm/jit/m68k/codegen.c
src/vm/jit/mips/codegen.c
src/vm/jit/mips/md-abi.c
src/vm/jit/oprofile-agent.hpp
src/vm/jit/optimizing/bytecode_escape.c
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/parse.c [deleted file]
src/vm/jit/parse.cpp [new file with mode: 0644]
src/vm/jit/parse.h [deleted file]
src/vm/jit/parse.hpp [new file with mode: 0644]
src/vm/jit/powerpc/codegen.c
src/vm/jit/powerpc/darwin/md-abi.c
src/vm/jit/powerpc/linux/md-abi.c
src/vm/jit/powerpc/netbsd/md-abi.c
src/vm/jit/powerpc64/codegen.c
src/vm/jit/powerpc64/linux/md-abi.c
src/vm/jit/reg.h
src/vm/jit/replace.cpp
src/vm/jit/replace.hpp
src/vm/jit/s390/codegen.c
src/vm/jit/s390/md-abi.c
src/vm/jit/show.cpp
src/vm/jit/sparc64/codegen.c
src/vm/jit/sparc64/md-abi.c
src/vm/jit/stack.c
src/vm/jit/stacktrace.cpp
src/vm/jit/stubs.cpp
src/vm/jit/stubs.hpp
src/vm/jit/trace.hpp
src/vm/jit/verify/Makefile.am
src/vm/jit/verify/icmds.c [deleted file]
src/vm/jit/verify/icmds.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-common.c [deleted file]
src/vm/jit/verify/typecheck-common.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-common.h [deleted file]
src/vm/jit/verify/typecheck-common.hpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-stackbased.c [deleted file]
src/vm/jit/verify/typecheck-stackbased.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-typeinferer.c [deleted file]
src/vm/jit/verify/typecheck-typeinferer.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-typeinferer.h [deleted file]
src/vm/jit/verify/typecheck-typeinferer.hpp [new file with mode: 0644]
src/vm/jit/verify/typecheck.c [deleted file]
src/vm/jit/verify/typecheck.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck.h [deleted file]
src/vm/jit/verify/typecheck.hpp [new file with mode: 0644]
src/vm/jit/verify/typeinfo.c [deleted file]
src/vm/jit/verify/typeinfo.cpp [new file with mode: 0644]
src/vm/jit/verify/typeinfo.h [deleted file]
src/vm/jit/verify/typeinfo.hpp [new file with mode: 0644]
src/vm/jit/x86_64/codegen.c
src/vm/jit/x86_64/md-abi.c
src/vm/linker.c [deleted file]
src/vm/linker.cpp [new file with mode: 0644]
src/vm/linker.h [deleted file]
src/vm/linker.hpp [new file with mode: 0644]
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/os.hpp
src/vm/primitive.hpp
src/vm/properties.cpp
src/vm/properties.hpp
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]
tests/regression/bugzilla/All.java
tests/regression/bugzilla/PR112.java [new file with mode: 0644]

diff --git a/INSTALL b/INSTALL
index f3869a941abc66166ca5ac152b1c526998c696cf..d3c5b40a94091285c27361905f591af64c1f7b21 100644 (file)
--- a/INSTALL
+++ b/INSTALL
-Quick start instructions
-========================
+Installation Instructions
+*************************
 
-You can check the configure options via `./configure --help'. But the
-default settings should be ok. For building the package type:
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007 Free Software Foundation, Inc.
 
-   $ ./configure
-   $ make
-   $ make install
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
 
-The default installation prefix is `/usr/local/cacao'. You can change
-this destination by providing the `--prefix=PATH' option to configure.
+Basic Installation
+==================
 
-This version of cacao only supports the `--prefix' option, even if
-configure processes the other options (`--bindir', `--libdir', etc.),
-it will screw up your installation since CACAO tries to setup a
-directory tree like the JVMs from Sun or IBM do.
+Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
 
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
 
-Requirements:
--------------
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  6. Often, you can also type `make uninstall' to remove the installed
+     files again.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
 
-In order to compile the Java classes from GNU classpath, you need a
-Java compiler supported by GNU classpath. To get a working classpath
-in an appropriate time, we recommend IBM jikes 1.18 or newer. For
-further instructions concerning GNU classpath, please refer to
-`src/classpath/INSTALL'.
index bfd698fb5f3836f4518e87e5fa041527e27c454d..9312ab4e99ee8d68aba26d7d9d9e85bcd8e1dda0 100644 (file)
@@ -67,13 +67,18 @@ m68k )
     JAVA_ARCH="m68k"
     ;;
 
-mips | mipsel )
+mips )
     ARCH_DIR="mips"
     ARCH_FLAGS="-D__MIPS__"
-    dnl Is this correct for mipsel?
     JAVA_ARCH="mips"
     ;;
 
+mipsel )
+    ARCH_DIR="mips"
+    ARCH_FLAGS="-D__MIPS__"
+    JAVA_ARCH="mipsel"
+    ;;
+
 powerpc )
     ARCH_DIR="powerpc"
     ARCH_FLAGS="-m32 -D__POWERPC__"
@@ -379,8 +384,6 @@ AC_CHECK_FUNCS([strlen])
 AC_CHECK_FUNCS([strncmp])
 AC_CHECK_FUNCS([strstr])
 AC_CHECK_FUNCS([time])
-AC_CHECK_FUNCS([va_end])
-AC_CHECK_FUNCS([va_start])
 AC_CHECK_FUNCS([write])
 
 
diff --git a/m4/jitcache.m4 b/m4/jitcache.m4
new file mode 100644 (file)
index 0000000..d873f30
--- /dev/null
@@ -0,0 +1,40 @@
+dnl m4/jitcache.m4
+dnl
+dnl Copyright (C) 2008
+dnl CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+dnl 
+dnl This file is part of CACAO.
+dnl 
+dnl This program is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU General Public License as
+dnl published by the Free Software Foundation; either version 2, or (at
+dnl your option) any later version.
+dnl 
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+dnl General Public License for more details.
+dnl 
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+dnl 02110-1301, USA.
+
+
+dnl check for jitcache support
+AC_DEFUN([AC_CHECK_ENABLE_JITCACHE],[
+AC_MSG_CHECKING(whether JIT compiler output caching should be enabled)
+AC_ARG_ENABLE([jitcache],
+              [AS_HELP_STRING(--enable-jitcache,enable caching of JIT compiler output [[default=no]])],
+              [case "${enableval}" in
+                   yes) ENABLE_JITCACHE=yes;;
+                   *) ENABLE_JITCACHE=no;;
+               esac],
+              [ENABLE_JITCACHE=no])
+AC_MSG_RESULT(${ENABLE_JITCACHE})
+AM_CONDITIONAL([ENABLE_JITCACHE], test x"${ENABLE_JITCACHE}" = "xyes")
+
+if test x"${ENABLE_JITCACHE}" = "xyes"; then
+    AC_DEFINE([ENABLE_JITCACHE], 1, [store and load JIT compiler output])
+fi
+])
index b828759d0cb5d6d204113ebe0ba82ca85dd023d6..e1377ac088e223ea88e3ab0d3a26db54201b9902 100644 (file)
 #     define DYNAMIC_LOADING
       extern int _end[];
 #     define DATAEND (_end)
-      extern int __data_start[];
-#     define DATASTART ((ptr_t)(__data_start))
+#     define SEARCH_FOR_DATA_START
 #     define CPP_WORDSZ _MIPS_SZPTR
 #     define ALIGNMENT (_MIPS_SZPTR/8)
 #     if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2
 #       define OS_TYPE "LINUX"
 #       define LINUX_STACKBOTTOM
 #       define DYNAMIC_LOADING
-       extern int __data_start[];
-#       define DATASTART ((ptr_t)(__data_start))
-    extern int _end[];
+#       define SEARCH_FOR_DATA_START
+        extern int _end[];
 #   define DATAEND (_end)
 #   define CACHE_LINE_SIZE 256
 #   define GETPAGESIZE() 4096
index b895797e4305c9ac5a9b6b854ae9b19b26c086eb..e34b5b3096eede44fa4110816193b559e349b958 100644 (file)
@@ -30,7 +30,7 @@
 #include "final.h"
 #include "heap.h"
 #include "mm/memory.h"
-#include "vm/finalizer.h"
+#include "vm/finalizer.hpp"
 
 
 /* Global Variables ***********************************************************/
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 e9fd6d50f66e34a5f5232eff0da07d1cb7bcaf71..deb86675a4c02c0a704ea0031c35524434fb3457 100644 (file)
@@ -44,7 +44,7 @@
 #include "mm/memory.h"
 #include "toolbox/logging.h"
 
-#include "vm/finalizer.h"
+#include "vm/finalizer.hpp"
 #include "vm/rt-timing.h"
 #include "vm/vm.hpp"
 
index 1a64e8626f3433442a55641478c35c2e6828b3c3..fedfb9abb750990dd7b339b972510ad343280603 100644 (file)
@@ -34,7 +34,7 @@
 #include "toolbox/logging.h"
 
 #include "vm/global.h"
-#include "vm/linker.h"
+#include "vm/linker.hpp"
 #include "vm/vm.hpp"
 
 
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 bfd612b010cf6be5879a74d721929707d003057f..c8dc49ba2ea09abfb77200cbd93ce35cd60ea07b 100644 (file)
@@ -45,7 +45,7 @@
 
 #include "vm/jit/builtin.hpp"
 #include "vm/exceptions.hpp"
-#include "vm/finalizer.h"
+#include "vm/finalizer.hpp"
 #include "vm/global.h"
 #include "vm/loader.hpp"
 #include "vm/options.h"
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..7e2c0b8359a2536f3a634e57d743ba1f983c16d0 100644 (file)
 
 #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"
 #include "vm/javaobjects.hpp"
-#include "vm/linker.h"
+#include "vm/linker.hpp"
 #include "vm/loader.hpp"
 #include "vm/options.h"
 #include "vm/primitive.hpp"
 #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 4d2edb56b0bd4048f68e627f0d289b02612d8800..c39f05866aefa52573980a0917b8e11c6de2c1ee 100644 (file)
@@ -41,7 +41,7 @@
 # include "native/vm/reflection.hpp"
 #endif
 
-#include "vm/access.h"
+#include "vm/access.hpp"
 #include "vm/jit/builtin.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/global.h"
index 61a20f73779d0f33909b504e45f416781758ce5c..e4cbf89a2e4cb5049fa8a01ec32cbdd717885e57 100644 (file)
@@ -41,7 +41,7 @@
 
 #include "native/vm/reflection.hpp"
 
-#include "vm/access.h"
+#include "vm/access.hpp"
 #include "vm/jit/builtin.hpp"
 #include "vm/class.hpp"
 #include "vm/exceptions.hpp"
@@ -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 1fc609c1d168e991debbca348f2edbec4c4ec93e..9b393d3bf53ab69f17260117462762223109a0e9 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"
@@ -2717,9 +2717,13 @@ jint JVM_Recv(jint fd, char *buf, jint nBytes, jint flags)
 
 jint JVM_Send(jint fd, char *buf, jint nBytes, jint flags)
 {
-       log_println("JVM_Send: IMPLEMENT ME!");
+       TRACEJVMCALLSENTER(("JVM_Send(fd=%d, buf=%p, nBytes=%d, flags=%d", fd, buf, nBytes, flags));
 
-       return 0;
+       int result = os::send(fd, buf, nBytes, flags);
+
+       TRACEJVMCALLSEXIT(("->%d", result));
+
+       return result;
 }
 
 
index c2745b9fbd3c1c0eaac1ae04b850039e207eb641..73a8545b8afef1b164d7e7987378f5782e0b7db4 100644 (file)
 
 #include "native/vm/reflection.hpp"
 
-#include "vm/access.h"
+#include "vm/access.hpp"
 #include "vm/jit/builtin.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/global.h"
 #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 950df13523d3fd106ff57418e2ce239cf1082fe6..bdba0c83a297d4022589d3980de4a76b184c89c8 100644 (file)
@@ -461,6 +461,39 @@ JNIEXPORT void JNICALL Java_sun_misc_Unsafe_putFloat__JF(JNIEnv *env, jobject _t
 }
 
 
+/*
+ * Class:     sun/misc/Unsafe
+ * Method:    getDouble
+ * Signature: (J)D
+ */
+JNIEXPORT jdouble JNICALL Java_sun_misc_Unsafe_getDouble__J(JNIEnv *env, jobject _this, jlong address)
+{
+       double *p;
+       double  value;
+
+       p = (double*) (intptr_t) address;
+
+       value = *p;
+
+       return value;
+}
+
+
+/*
+ * Class:     sun/misc/Unsafe
+ * Method:    putDouble
+ * Signature: (JD)V
+ */
+JNIEXPORT void JNICALL Java_sun_misc_Unsafe_putDouble__JD(JNIEnv *env, jobject _this, jlong address, jdouble value)
+{
+       double* p;
+
+       p = (double*) (intptr_t) address;
+
+       *p = value;
+}
+
+
 /*
  * Class:     sun/misc/Unsafe
  * Method:    objectFieldOffset
@@ -1126,6 +1159,8 @@ static JNINativeMethod methods[] = {
        { (char*) "putLong",                (char*) "(JJ)V",                                                      (void*) (uintptr_t) &Java_sun_misc_Unsafe_putLong__JJ                      },
        { (char*) "getFloat",               (char*) "(J)F",                                                       (void*) (uintptr_t) &Java_sun_misc_Unsafe_getFloat__J                      },
        { (char*) "putFloat",               (char*) "(JF)V",                                                      (void*) (uintptr_t) &Java_sun_misc_Unsafe_putFloat__JF                     },
+       { (char*) "getDouble",              (char*) "(J)D",                                                       (void*) (uintptr_t) &Java_sun_misc_Unsafe_getDouble__J                     },
+       { (char*) "putDouble",              (char*) "(JD)V",                                                      (void*) (uintptr_t) &Java_sun_misc_Unsafe_putDouble__JD                    },
        { (char*) "objectFieldOffset",      (char*) "(Ljava/lang/reflect/Field;)J",                               (void*) (uintptr_t) &Java_sun_misc_Unsafe_objectFieldOffset                },
        { (char*) "allocateMemory",         (char*) "(J)J",                                                       (void*) (uintptr_t) &Java_sun_misc_Unsafe_allocateMemory                   },
 #if 0
index 5bcee690db131362a170ab9dbd3d3132e8afce3b..7df64763527b45a3601f080d3a81da02b7c422f7 100644 (file)
@@ -46,7 +46,7 @@
 #include "toolbox/list.hpp"
 
 #include "vm/exceptions.hpp"
-#include "vm/finalizer.h"
+#include "vm/finalizer.hpp"
 #include "vm/global.h"
 #include "vm/options.h"
 #include "vm/string.hpp"
index 3cad59663bb13114e129be8fbcef0585dc1735bc..fefb4a34f662c6465c63b023f1d3416ccf01a849 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..677a10663202619f0175946ec45fcf9f7a6cb1ac 100644 (file)
@@ -65,8 +65,8 @@ endif
 
 if ENABLE_ZLIB
 ZLIB_SOURCES = \
-       zip.c \
-       zip.h
+       zip.cpp \
+       zip.hpp
 endif
 
 noinst_HEADERS = \
@@ -77,37 +77,37 @@ noinst_LTLIBRARIES = \
        libvm.la
 
 libvm_la_SOURCES = \
-       access.c \
-       access.h \
+       access.cpp \
+       access.hpp \
        $(ANNOTATION_SOURCES) \
        array.cpp \
        array.hpp \
        $(ASSERTION_SOURCES) \
        class.cpp \
        class.hpp \
-       classcache.c \
-       classcache.h \
+       classcache.cpp \
+       classcache.hpp \
        $(CYCLES_STATS_SOURCES) \
-       descriptor.c \
-       descriptor.h \
+       descriptor.cpp \
+       descriptor.hpp \
        exceptions.cpp \
        exceptions.hpp \
        field.cpp \
        field.hpp \
-       finalizer.c \
-       finalizer.h \
+       finalizer.cpp \
+       finalizer.hpp \
        globals.cpp \
        globals.hpp \
        initialize.cpp \
        initialize.hpp \
        javaobjects.cpp \
        javaobjects.hpp \
-       linker.c \
-       linker.h \
+       linker.cpp \
+       linker.hpp \
        loader.cpp \
        loader.hpp \
-       method.c \
-       method.h \
+       method.cpp \
+       method.hpp \
        options.c \
        options.h \
        os.cpp \
diff --git a/src/vm/access.c b/src/vm/access.c
deleted file mode 100644 (file)
index bd21bd7..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/* src/vm/access.c - checking access rights
-
-   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 <string.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "native/llni.h"
-
-#include "vm/access.h"
-#include "vm/jit/builtin.hpp"
-#include "vm/class.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/field.hpp"
-#include "vm/globals.hpp"
-#include "vm/method.h"
-
-#include "vm/jit/stacktrace.hpp"
-
-
-/* access_is_accessible_class **************************************************
-   Check if a class is accessible from another class
-  
-   IN:
-       referer..........the class containing the reference
-       cls..............the result of resolving the reference
-  
-   RETURN VALUE:
-       true.............access permitted
-       false............access denied
-   
-   NOTE:
-       This function performs the checks listed in section 5.4.4.
-          "Access Control" of "The Java(TM) Virtual Machine Specification,
-          Second Edition".
-
-*******************************************************************************/
-
-bool access_is_accessible_class(classinfo *referer, classinfo *cls)
-{
-       assert(referer);
-       assert(cls);
-
-       /* Public classes are always accessible. */
-
-       if (cls->flags & ACC_PUBLIC)
-               return true;
-
-       /* A class in the same package is always accessible. */
-
-       if (SAME_PACKAGE(referer, cls))
-               return true;
-
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-       /* Code for Sun's OpenJDK (see
-          hotspot/src/share/vm/runtime/reflection.cpp
-          (Reflection::verify_class_access)): Allow all accesses from
-          sun/reflect/MagicAccessorImpl subclasses to succeed
-          trivially. */
-
-       /* NOTE: This check must be before checks that could return
-          false. */
-
-       if (class_issubclass(referer, class_sun_reflect_MagicAccessorImpl))
-               return true;
-#endif
-
-       /* A non-public class in another package is not accessible. */
-
-       return false;
-}
-
-
-/* access_is_accessible_member *************************************************
-   Check if a field or method is accessible from a given class
-  
-   IN:
-       referer..........the class containing the reference
-       declarer.........the class declaring the member
-       memberflags......the access flags of the member
-  
-   RETURN VALUE:
-       true.............access permitted
-       false............access denied
-
-   NOTE:
-       This function only performs the checks listed in section 5.4.4.
-          "Access Control" of "The Java(TM) Virtual Machine Specification,
-          Second Edition".
-
-          In particular a special condition for protected access with is
-          part of the verification process according to the spec is not
-          checked in this function.
-   
-*******************************************************************************/
-
-bool access_is_accessible_member(classinfo *referer, classinfo *declarer,
-                                                                s4 memberflags)
-{
-       assert(referer);
-       assert(declarer);
-
-       /* Public members are accessible. */
-
-       if (memberflags & ACC_PUBLIC)
-               return true;
-
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-       /* Code for Sun's OpenJDK (see
-          hotspot/src/share/vm/runtime/reflection.cpp
-          (Reflection::verify_class_access)): Allow all accesses from
-          sun/reflect/MagicAccessorImpl subclasses to succeed
-          trivially. */
-
-       /* NOTE: This check must be before checks that could return
-          false. */
-
-       if (class_issubclass(referer, class_sun_reflect_MagicAccessorImpl))
-               return true;
-#endif
-
-       /* {declarer is not an interface} */
-
-       /* private members are only accessible by the class itself */
-
-       if (memberflags & ACC_PRIVATE)
-               return (referer == declarer);
-
-       /* {the member is protected or package private} */
-
-       /* protected and package private members are accessible in the
-          same package */
-
-       if (SAME_PACKAGE(referer, declarer))
-               return true;
-
-       /* package private members are not accessible outside the package */
-
-       if (!(memberflags & ACC_PROTECTED))
-               return false;
-
-       /* {the member is protected and declarer is in another package} */
-
-       /* a necessary condition for access is that referer is a subclass
-          of declarer */
-
-       assert((referer->state & CLASS_LINKED) && (declarer->state & CLASS_LINKED));
-
-       if (class_isanysubclass(referer, declarer))
-               return true;
-
-       return false;
-}
-
-
-/* access_check_field **********************************************************
-   Check if the (indirect) caller has access rights to the specified
-   field.
-  
-   IN:
-       f................the field to check
-          callerdepth......number of callers to ignore
-                           For example if the stacktrace looks like this:
-
-                                  [0] java.lang.reflect.Method.invokeNative (Native Method)
-                                  [1] java.lang.reflect.Method.invoke
-                                  [2] <caller>
-
-                                       you must specify 2 so the access rights of <caller> 
-                                               are checked.
-  
-   RETURN VALUE:
-       true.............access permitted
-       false............access denied, an exception has been thrown
-   
-*******************************************************************************/
-
-#if defined(ENABLE_JAVASE)
-bool access_check_field(fieldinfo *f, int callerdepth)
-{
-       classinfo *callerclass;
-       char      *msg;
-       int        msglen;
-       utf       *u;
-
-       /* If everything is public, there is nothing to check. */
-
-       if ((f->clazz->flags & ACC_PUBLIC) && (f->flags & ACC_PUBLIC))
-               return true;
-
-       /* Get the caller's class. */
-
-       callerclass = stacktrace_get_caller_class(callerdepth);
-
-       if (callerclass == NULL)
-               return false;
-
-       /* Check access rights. */
-
-       if (!access_is_accessible_member(callerclass, f->clazz, f->flags)) {
-               msglen =
-                       utf_bytes(f->clazz->name) +
-                       strlen(".") +
-                       utf_bytes(f->name) +
-                       strlen(" not accessible from ") +
-                       utf_bytes(callerclass->name) +
-                       strlen("0");
-
-               msg = MNEW(char, msglen);
-
-               utf_copy_classname(msg, f->clazz->name);
-               strcat(msg, ".");
-               utf_cat_classname(msg, f->name);
-               strcat(msg, " not accessible from ");
-               utf_cat_classname(msg, callerclass->name);
-
-               u = utf_new_char(msg);
-
-               MFREE(msg, char, msglen);
-               
-               exceptions_throw_illegalaccessexception(u);
-
-               return false;
-       }
-
-       /* access granted */
-
-       return true;
-}
-#endif
-
-
-/* access_check_method *********************************************************
-   Check if the (indirect) caller has access rights to the specified
-   method.
-  
-   IN:
-       m................the method to check
-          callerdepth......number of callers to ignore
-                           For example if the stacktrace looks like this:
-
-                                  [1] java.lang.reflect.Method.invokeNative (Native Method)
-                                  [1] java.lang.reflect.Method.invoke
-                                  [2] <caller>
-
-                                       you must specify 2 so the access rights of <caller> 
-                                               are checked.
-  
-   RETURN VALUE:
-       true.............access permitted
-       false............access denied, an exception has been thrown
-   
-*******************************************************************************/
-
-#if defined(ENABLE_JAVASE)
-bool access_check_method(methodinfo *m, int callerdepth)
-{
-       classinfo *callerclass;
-       char      *msg;
-       int        msglen;
-       utf       *u;
-
-       /* If everything is public, there is nothing to check. */
-
-       if ((m->clazz->flags & ACC_PUBLIC) && (m->flags & ACC_PUBLIC))
-               return true;
-
-       /* Get the caller's class. */
-
-       callerclass = stacktrace_get_caller_class(callerdepth);
-
-       if (callerclass == NULL)
-               return false;
-
-       /* Check access rights. */
-
-       if (!access_is_accessible_member(callerclass, m->clazz, m->flags)) {
-               msglen =
-                       utf_bytes(m->clazz->name) +
-                       strlen(".") +
-                       utf_bytes(m->name) +
-                       utf_bytes(m->descriptor) +
-                       strlen(" not accessible from ") +
-                       utf_bytes(callerclass->name) +
-                       strlen("0");
-
-               msg = MNEW(char, msglen);
-
-               utf_copy_classname(msg, m->clazz->name);
-               strcat(msg, ".");
-               utf_cat_classname(msg, m->name);
-               utf_cat_classname(msg, m->descriptor);
-               strcat(msg, " not accessible from ");
-               utf_cat_classname(msg, callerclass->name);
-
-               u = utf_new_char(msg);
-
-               MFREE(msg, char, msglen);
-               
-               exceptions_throw_illegalaccessexception(u);
-
-               return false;
-       }
-
-       /* access granted */
-
-       return true;
-}
-#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/access.cpp b/src/vm/access.cpp
new file mode 100644 (file)
index 0000000..a0abbc1
--- /dev/null
@@ -0,0 +1,364 @@
+/* src/vm/access.c - checking access rights
+
+   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 <string.h>
+
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "native/llni.h"
+
+#include "vm/access.hpp"
+#include "vm/jit/builtin.hpp"
+#include "vm/class.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/field.hpp"
+#include "vm/globals.hpp"
+#include "vm/method.hpp"
+
+#include "vm/jit/stacktrace.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* access_is_accessible_class **************************************************
+   Check if a class is accessible from another class
+  
+   IN:
+       referer..........the class containing the reference
+       cls..............the result of resolving the reference
+  
+   RETURN VALUE:
+       true.............access permitted
+       false............access denied
+   
+   NOTE:
+       This function performs the checks listed in section 5.4.4.
+          "Access Control" of "The Java(TM) Virtual Machine Specification,
+          Second Edition".
+
+*******************************************************************************/
+
+bool access_is_accessible_class(classinfo *referer, classinfo *cls)
+{
+       assert(referer);
+       assert(cls);
+
+       /* Public classes are always accessible. */
+
+       if (cls->flags & ACC_PUBLIC)
+               return true;
+
+       /* A class in the same package is always accessible. */
+
+       if (SAME_PACKAGE(referer, cls))
+               return true;
+
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+       /* Code for Sun's OpenJDK (see
+          hotspot/src/share/vm/runtime/reflection.cpp
+          (Reflection::verify_class_access)): Allow all accesses from
+          sun/reflect/MagicAccessorImpl subclasses to succeed
+          trivially. */
+
+       /* NOTE: This check must be before checks that could return
+          false. */
+
+       if (class_issubclass(referer, class_sun_reflect_MagicAccessorImpl))
+               return true;
+#endif
+
+       /* A non-public class in another package is not accessible. */
+
+       return false;
+}
+
+
+/* access_is_accessible_member *************************************************
+   Check if a field or method is accessible from a given class
+  
+   IN:
+       referer..........the class containing the reference
+       declarer.........the class declaring the member
+       memberflags......the access flags of the member
+  
+   RETURN VALUE:
+       true.............access permitted
+       false............access denied
+
+   NOTE:
+       This function only performs the checks listed in section 5.4.4.
+          "Access Control" of "The Java(TM) Virtual Machine Specification,
+          Second Edition".
+
+          In particular a special condition for protected access with is
+          part of the verification process according to the spec is not
+          checked in this function.
+   
+*******************************************************************************/
+
+bool access_is_accessible_member(classinfo *referer, classinfo *declarer,
+                                                                s4 memberflags)
+{
+       assert(referer);
+       assert(declarer);
+
+       /* Public members are accessible. */
+
+       if (memberflags & ACC_PUBLIC)
+               return true;
+
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+       /* Code for Sun's OpenJDK (see
+          hotspot/src/share/vm/runtime/reflection.cpp
+          (Reflection::verify_class_access)): Allow all accesses from
+          sun/reflect/MagicAccessorImpl subclasses to succeed
+          trivially. */
+
+       /* NOTE: This check must be before checks that could return
+          false. */
+
+       if (class_issubclass(referer, class_sun_reflect_MagicAccessorImpl))
+               return true;
+#endif
+
+       /* {declarer is not an interface} */
+
+       /* private members are only accessible by the class itself */
+
+       if (memberflags & ACC_PRIVATE)
+               return (referer == declarer);
+
+       /* {the member is protected or package private} */
+
+       /* protected and package private members are accessible in the
+          same package */
+
+       if (SAME_PACKAGE(referer, declarer))
+               return true;
+
+       /* package private members are not accessible outside the package */
+
+       if (!(memberflags & ACC_PROTECTED))
+               return false;
+
+       /* {the member is protected and declarer is in another package} */
+
+       /* a necessary condition for access is that referer is a subclass
+          of declarer */
+
+       assert((referer->state & CLASS_LINKED) && (declarer->state & CLASS_LINKED));
+
+       if (class_isanysubclass(referer, declarer))
+               return true;
+
+       return false;
+}
+
+
+/* access_check_field **********************************************************
+   Check if the (indirect) caller has access rights to the specified
+   field.
+  
+   IN:
+       f................the field to check
+          callerdepth......number of callers to ignore
+                           For example if the stacktrace looks like this:
+
+                                  [0] java.lang.reflect.Method.invokeNative (Native Method)
+                                  [1] java.lang.reflect.Method.invoke
+                                  [2] <caller>
+
+                                       you must specify 2 so the access rights of <caller> 
+                                               are checked.
+  
+   RETURN VALUE:
+       true.............access permitted
+       false............access denied, an exception has been thrown
+   
+*******************************************************************************/
+
+#if defined(ENABLE_JAVASE)
+bool access_check_field(fieldinfo *f, int callerdepth)
+{
+       classinfo *callerclass;
+       char      *msg;
+       int        msglen;
+       utf       *u;
+
+       /* If everything is public, there is nothing to check. */
+
+       if ((f->clazz->flags & ACC_PUBLIC) && (f->flags & ACC_PUBLIC))
+               return true;
+
+       /* Get the caller's class. */
+
+       callerclass = stacktrace_get_caller_class(callerdepth);
+
+       if (callerclass == NULL)
+               return false;
+
+       /* Check access rights. */
+
+       if (!access_is_accessible_member(callerclass, f->clazz, f->flags)) {
+               msglen =
+                       utf_bytes(f->clazz->name) +
+                       strlen(".") +
+                       utf_bytes(f->name) +
+                       strlen(" not accessible from ") +
+                       utf_bytes(callerclass->name) +
+                       strlen("0");
+
+               msg = MNEW(char, msglen);
+
+               utf_copy_classname(msg, f->clazz->name);
+               strcat(msg, ".");
+               utf_cat_classname(msg, f->name);
+               strcat(msg, " not accessible from ");
+               utf_cat_classname(msg, callerclass->name);
+
+               u = utf_new_char(msg);
+
+               MFREE(msg, char, msglen);
+               
+               exceptions_throw_illegalaccessexception(u);
+
+               return false;
+       }
+
+       /* access granted */
+
+       return true;
+}
+#endif
+
+
+/* access_check_method *********************************************************
+   Check if the (indirect) caller has access rights to the specified
+   method.
+  
+   IN:
+       m................the method to check
+          callerdepth......number of callers to ignore
+                           For example if the stacktrace looks like this:
+
+                                  [1] java.lang.reflect.Method.invokeNative (Native Method)
+                                  [1] java.lang.reflect.Method.invoke
+                                  [2] <caller>
+
+                                       you must specify 2 so the access rights of <caller> 
+                                               are checked.
+  
+   RETURN VALUE:
+       true.............access permitted
+       false............access denied, an exception has been thrown
+   
+*******************************************************************************/
+
+#if defined(ENABLE_JAVASE)
+bool access_check_method(methodinfo *m, int callerdepth)
+{
+       classinfo *callerclass;
+       char      *msg;
+       int        msglen;
+       utf       *u;
+
+       /* If everything is public, there is nothing to check. */
+
+       if ((m->clazz->flags & ACC_PUBLIC) && (m->flags & ACC_PUBLIC))
+               return true;
+
+       /* Get the caller's class. */
+
+       callerclass = stacktrace_get_caller_class(callerdepth);
+
+       if (callerclass == NULL)
+               return false;
+
+       /* Check access rights. */
+
+       if (!access_is_accessible_member(callerclass, m->clazz, m->flags)) {
+               msglen =
+                       utf_bytes(m->clazz->name) +
+                       strlen(".") +
+                       utf_bytes(m->name) +
+                       utf_bytes(m->descriptor) +
+                       strlen(" not accessible from ") +
+                       utf_bytes(callerclass->name) +
+                       strlen("0");
+
+               msg = MNEW(char, msglen);
+
+               utf_copy_classname(msg, m->clazz->name);
+               strcat(msg, ".");
+               utf_cat_classname(msg, m->name);
+               utf_cat_classname(msg, m->descriptor);
+               strcat(msg, " not accessible from ");
+               utf_cat_classname(msg, callerclass->name);
+
+               u = utf_new_char(msg);
+
+               MFREE(msg, char, msglen);
+               
+               exceptions_throw_illegalaccessexception(u);
+
+               return false;
+       }
+
+       /* access granted */
+
+       return true;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#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/access.h b/src/vm/access.h
deleted file mode 100644 (file)
index 59c6ef7..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/* src/vm/access.h - checking access rights
-
-   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 _ACCESS_H
-#define _ACCESS_H
-
-#include "config.h"
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "vm/class.hpp"
-#include "vm/field.hpp"
-#include "vm/global.h"
-#include "vm/method.h"
-
-
-/* macros *********************************************************************/
-
-#define SAME_PACKAGE(a,b)                                  \
-                       ((a)->classloader == (b)->classloader &&       \
-                        (a)->packagename == (b)->packagename)
-
-
-/* function prototypes ********************************************************/
-
-bool access_is_accessible_class(classinfo *referer, classinfo *cls);
-
-bool access_is_accessible_member(classinfo *referer, classinfo *declarer,
-                                                                int32_t memberflags);
-
-#if defined(ENABLE_JAVASE)
-bool access_check_field(fieldinfo *f, int callerdepth);
-bool access_check_method(methodinfo *m, int callerdepth);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ACCESS_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/access.hpp b/src/vm/access.hpp
new file mode 100644 (file)
index 0000000..9ec44c9
--- /dev/null
@@ -0,0 +1,82 @@
+/* src/vm/access.h - checking access rights
+
+   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 _ACCESS_H
+#define _ACCESS_H
+
+#include "config.h"
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "vm/class.hpp"
+#include "vm/field.hpp"
+#include "vm/global.h"
+#include "vm/method.hpp"
+
+
+/* macros *********************************************************************/
+
+#define SAME_PACKAGE(a,b)                                  \
+                       ((a)->classloader == (b)->classloader &&       \
+                        (a)->packagename == (b)->packagename)
+
+
+/* function prototypes ********************************************************/
+
+bool access_is_accessible_class(classinfo *referer, classinfo *cls);
+
+bool access_is_accessible_member(classinfo *referer, classinfo *declarer,
+                                                                int32_t memberflags);
+
+#if defined(ENABLE_JAVASE)
+bool access_check_field(fieldinfo *f, int callerdepth);
+bool access_check_method(methodinfo *m, int callerdepth);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ACCESS_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 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 6444cbb6750449a5b869fa7416a54b6dd12311c1..2e941b10b5d28ff968adea73052ef291a4d31d70 100644 (file)
 #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"
 #include "vm/javaobjects.hpp"
-#include "vm/linker.h"
+#include "vm/linker.hpp"
 #include "vm/loader.hpp"
 #include "vm/options.h"
 #include "vm/resolve.hpp"
index c82e4bf244092e56f767483fe2c2715f29f0b559..d1584b1c4228073671997988bbf27eb9038c663c 100644 (file)
@@ -45,9 +45,9 @@ typedef struct extra_classref extra_classref;
 
 #include "vm/field.hpp"
 #include "vm/global.h"
-#include "vm/linker.h"
+#include "vm/linker.hpp"
 #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..93db61a
--- /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..aef65e2
--- /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:
+ */
+
diff --git a/src/vm/descriptor.c b/src/vm/descriptor.c
deleted file mode 100644 (file)
index 235154e..0000000
+++ /dev/null
@@ -1,1398 +0,0 @@
-/* src/vm/descriptor.c - checking and parsing of field / method descriptors
-
-   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 "md-abi.h"
-
-#include "mm/memory.h"
-
-#include "vm/descriptor.h"
-#include "vm/exceptions.hpp"
-#include "vm/options.h"
-#include "vm/primitive.hpp"
-#include "vm/vm.hpp"
-
-#include "vm/jit/abi.h"
-
-
-/* constants (private to descriptor.c) ****************************************/
-
-/* initial number of entries for the classrefhash of a descriptor_pool */
-/* (currently the hash is never grown!) */
-#define CLASSREFHASH_INIT_SIZE  64
-
-/* initial number of entries for the descriptorhash of a descriptor_pool */
-/* (currently the hash is never grown!) */
-#define DESCRIPTORHASH_INIT_SIZE  128
-
-/* data structures (private to descriptor.c) **********************************/
-
-typedef struct classref_hash_entry classref_hash_entry;
-typedef struct descriptor_hash_entry descriptor_hash_entry;
-
-/* entry struct for the classrefhash of descriptor_pool */
-struct classref_hash_entry {
-       classref_hash_entry *hashlink;  /* for hash chaining            */
-       utf                 *name;      /* name of the class refered to */
-       u2                   index;     /* index into classref table    */
-};
-
-/* entry struct for the descriptorhash of descriptor_pool */
-struct descriptor_hash_entry {
-       descriptor_hash_entry *hashlink;
-       utf                   *desc;
-       parseddesc_t           parseddesc;
-       s2                     paramslots; /* number of params, LONG/DOUBLE counted as 2 */
-};
-
-
-/****************************************************************************/
-/* MACROS FOR DESCRIPTOR PARSING (private to descriptor.c)                  */
-/****************************************************************************/
-
-/* SKIP_FIELDDESCRIPTOR:
- * utf_ptr must point to the first character of a field descriptor.
- * After the macro call utf_ptr points to the first character after
- * the field descriptor.
- *
- * CAUTION: This macro does not check for an unexpected end of the
- * descriptor. Better use SKIP_FIELDDESCRIPTOR_SAFE.
- */
-#define SKIP_FIELDDESCRIPTOR(utf_ptr)                                                  \
-       do { while (*(utf_ptr)=='[') (utf_ptr)++;                                       \
-               if (*(utf_ptr)++=='L')                                                                  \
-                       while(*(utf_ptr)++ != ';') /* skip */; } while(0)
-
-/* SKIP_FIELDDESCRIPTOR_SAFE:
- * utf_ptr must point to the first character of a field descriptor.
- * After the macro call utf_ptr points to the first character after
- * the field descriptor.
- *
- * Input:
- *     utf_ptr....points to first char of descriptor
- *     end_ptr....points to first char after the end of the string
- *     errorflag..must be initialized (to false) by the caller!
- * Output:
- *     utf_ptr....points to first char after the descriptor
- *     errorflag..set to true if the string ended unexpectedly
- */
-#define SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,errorflag)                   \
-       do { while ((utf_ptr) != (end_ptr) && *(utf_ptr)=='[') (utf_ptr)++;     \
-               if ((utf_ptr) == (end_ptr))                                                                             \
-                       (errorflag) = true;                                                                                     \
-               else                                                                                                                    \
-                       if (*(utf_ptr)++=='L') {                                                                        \
-                               while((utf_ptr) != (end_ptr) && *(utf_ptr)++ != ';')    \
-                                       /* skip */;                                                                                     \
-                               if ((utf_ptr)[-1] != ';')                                                               \
-                                       (errorflag) = true; }} while(0)
-
-
-/****************************************************************************/
-/* DEBUG HELPERS                                                            */
-/****************************************************************************/
-
-/*#define DESCRIPTOR_VERBOSE*/
-
-/****************************************************************************/
-/* FUNCTIONS                                                                */
-/****************************************************************************/
-
-/* descriptor_to_basic_type ****************************************************
-
-   Return the basic type to use for a value with this descriptor.
-
-   IN:
-       utf..............descriptor utf string
-
-   OUT:
-       A TYPE_* constant.
-
-   PRECONDITIONS:
-       This function assumes that the descriptor has passed 
-          descriptor_pool_add checks and that it does not start with '('.
-
-*******************************************************************************/
-
-int descriptor_to_basic_type(utf *descriptor)
-{
-       assert(descriptor->blength >= 1);
-       
-       switch (descriptor->text[0]) {
-       case 'Z':
-       case 'B':
-       case 'C':
-       case 'S':
-       case 'I':
-               return TYPE_INT;
-
-       case 'J':
-               return TYPE_LNG;
-
-       case 'F':
-               return TYPE_FLT;
-
-       case 'D':
-               return TYPE_DBL;
-
-       case 'L':
-       case '[':
-               return TYPE_ADR;
-
-       default:
-               vm_abort("descriptor_to_basic_type: invalid type %c",
-                                descriptor->text[0]);
-       }
-
-       /* keep the compiler happy */
-
-       return 0;
-}
-
-
-/* descriptor_typesize *********************************************************
-
-   Return the size in bytes needed for the given type.
-
-   IN:
-       td..............typedesc describing the type
-
-   OUT:
-       The number of bytes
-
-*******************************************************************************/
-
-int descriptor_typesize(typedesc *td)
-{
-       assert(td);
-
-       switch (td->type) {
-       case TYPE_INT:
-       case TYPE_FLT:
-               return 4;
-
-       case TYPE_LNG:
-       case TYPE_DBL:
-               return 8;
-
-       case TYPE_ADR:
-               return SIZEOF_VOID_P;
-
-       default:
-               vm_abort("descriptor_typesize: invalid type %d", td->type);
-       }
-
-       /* keep the compiler happy */
-
-       return 0;
-}
-
-
-/* name_from_descriptor ********************************************************
-
-   Return the class name indicated by the given descriptor
-   (Internally used helper function)
-
-   IN:
-       c................class containing the descriptor
-       utf_ptr..........first character of descriptor
-       end_ptr..........first character after the end of the string
-       mode.............a combination (binary or) of the following flags:
-
-               (Flags marked with * are the default settings.)
-
-               How to handle "V" descriptors:
-
-                            * DESCRIPTOR_VOID.....handle it like other primitive types
-                   DESCRIPTOR_NOVOID...treat it as an error
-
-               How to deal with extra characters after the end of the
-               descriptor:
-
-                            * DESCRIPTOR_NOCHECKEND...ignore (useful for parameter lists)
-                   DESCRIPTOR_CHECKEND.....treat them as an error
-
-   OUT:
-       *next............if non-NULL, *next is set to the first character after
-                        the descriptor. (Undefined if an error occurs.)
-       *name............set to the utf name of the class
-
-   RETURN VALUE:
-       true.............descriptor parsed successfully
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-#define DESCRIPTOR_VOID          0      /* default */
-#define DESCRIPTOR_NOVOID        0x0040
-#define DESCRIPTOR_NOCHECKEND    0      /* default */
-#define DESCRIPTOR_CHECKEND      0x1000
-
-static bool 
-name_from_descriptor(classinfo *c,
-                                        char *utf_ptr, char *end_ptr,
-                                        char **next, int mode, utf **name)
-{
-       char *start = utf_ptr;
-       bool error = false;
-
-       assert(c);
-       assert(utf_ptr);
-       assert(end_ptr);
-       assert(name);
-       
-       *name = NULL;           
-       SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error);
-
-       if (mode & DESCRIPTOR_CHECKEND)
-               error |= (utf_ptr != end_ptr);
-       
-       if (!error) {
-               if (next) *next = utf_ptr;
-               
-               switch (*start) {
-                 case 'V':
-                         if (mode & DESCRIPTOR_NOVOID)
-                                 break;
-                         /* FALLTHROUGH! */
-                 case 'I':
-                 case 'J':
-                 case 'F':
-                 case 'D':
-                 case 'B':
-                 case 'C':
-                 case 'S':
-                 case 'Z':
-                         return true;
-                         
-                 case 'L':
-                         start++;
-                         utf_ptr--;
-                         /* FALLTHROUGH! */
-                 case '[':
-                         *name = utf_new(start, utf_ptr - start);
-                         return true;
-               }
-       }
-
-       exceptions_throw_classformaterror(c, "Invalid descriptor");
-       return false;
-}
-
-
-/* descriptor_to_typedesc ******************************************************
-   Parse the given type descriptor and fill a typedesc struct
-   (Internally used helper function)
-
-   IN:
-       pool.............the descriptor pool
-          utf_ptr..........points to first character of type descriptor
-          end_pos..........points after last character of the whole descriptor
-
-   OUT:
-       *next............set to next character after type descriptor
-          *d...............filled with parsed information
-
-   RETURN VALUE:
-       true.............parsing succeeded  
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-static bool
-descriptor_to_typedesc(descriptor_pool *pool, char *utf_ptr, char *end_pos,
-                                          char **next, typedesc *td)
-{
-       utf *name;
-       
-       if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, next, 0, &name))
-               return false;
-
-       if (name) {
-               /* a reference type */
-               td->type = TYPE_ADR;
-               td->primitivetype = TYPE_ADR;
-               td->arraydim = 0;
-               for (utf_ptr = name->text; *utf_ptr == '['; ++utf_ptr)
-                       td->arraydim++;
-               td->classref = descriptor_pool_lookup_classref(pool, name);
-
-       } else {
-               /* a primitive type */
-               switch (*utf_ptr) {
-               case 'B': 
-                       td->primitivetype = PRIMITIVETYPE_BYTE;
-                       td->type = TYPE_INT;
-                       break;
-               case 'C':
-                       td->primitivetype = PRIMITIVETYPE_CHAR;
-                       td->type = TYPE_INT;
-                       break;
-               case 'S':  
-                       td->primitivetype = PRIMITIVETYPE_SHORT;
-                       td->type = TYPE_INT;
-                       break;
-               case 'Z':
-                       td->primitivetype = PRIMITIVETYPE_BOOLEAN;
-                       td->type = TYPE_INT;
-                       break;
-               case 'I':
-                       td->primitivetype = PRIMITIVETYPE_INT;
-                       td->type = TYPE_INT;
-                       break;
-               case 'D':
-                       td->primitivetype = PRIMITIVETYPE_DOUBLE;
-                       td->type = TYPE_DBL;
-                       break;
-               case 'F':
-                       td->primitivetype = PRIMITIVETYPE_FLOAT;
-                       td->type = TYPE_FLT;
-                       break;
-               case 'J':
-                       td->primitivetype = PRIMITIVETYPE_LONG;
-                       td->type = TYPE_LNG;
-                       break;
-               case 'V':
-                       td->primitivetype = PRIMITIVETYPE_VOID;
-                       td->type = TYPE_VOID;
-                       break;
-               default:
-                       assert(false);
-               }
-
-               td->arraydim = 0;
-               td->classref = NULL;
-       }
-
-       return true;
-}
-
-
-/* descriptor_pool_new *********************************************************
-   Allocate a new descriptor_pool
-
-   IN:
-       referer..........class for which to create the pool
-
-   RETURN VALUE:
-       a pointer to the new descriptor_pool
-
-*******************************************************************************/
-
-descriptor_pool * 
-descriptor_pool_new(classinfo *referer)
-{
-       descriptor_pool *pool;
-       u4 hashsize;
-       u4 slot;
-
-       pool = DNEW(descriptor_pool);
-       assert(pool);
-
-       pool->referer = referer;
-       pool->fieldcount = 0;
-       pool->methodcount = 0;
-       pool->paramcount = 0;
-       pool->descriptorsize = 0;
-       pool->descriptors = NULL;
-       pool->descriptors_next = NULL;
-       pool->classrefs = NULL;
-       pool->descriptor_kind = NULL;
-       pool->descriptor_kind_next = NULL;
-
-       hashsize = CLASSREFHASH_INIT_SIZE;
-       pool->classrefhash.size = hashsize;
-       pool->classrefhash.entries = 0;
-       pool->classrefhash.ptr = DMNEW(void*, hashsize);
-       for (slot=0; slot<hashsize; ++slot)
-               pool->classrefhash.ptr[slot] = NULL;
-
-       hashsize = DESCRIPTORHASH_INIT_SIZE;
-       pool->descriptorhash.size = hashsize;
-       pool->descriptorhash.entries = 0;
-       pool->descriptorhash.ptr = DMNEW(void*, hashsize);
-       for (slot=0; slot<hashsize; ++slot)
-               pool->descriptorhash.ptr[slot] = NULL;
-
-       return pool;
-}
-
-
-/* descriptor_pool_add_class ***************************************************
-   Add the given class reference to the pool
-
-   IN:
-       pool.............the descriptor_pool
-          name.............the class reference to add
-
-   RETURN VALUE:
-       true.............reference has been added
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool 
-descriptor_pool_add_class(descriptor_pool *pool, utf *name)
-{
-       u4 key,slot;
-       classref_hash_entry *c;
-       
-       assert(pool);
-       assert(name);
-
-#ifdef DESCRIPTOR_VERBOSE
-       fprintf(stderr,"descriptor_pool_add_class(%p,",(void*)pool);
-       utf_fprint_printable_ascii(stderr,name);fprintf(stderr,")\n");
-#endif
-
-       /* find a place in the hashtable */
-
-       key = utf_hashkey(name->text, name->blength);
-       slot = key & (pool->classrefhash.size - 1);
-       c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
-
-       while (c) {
-               if (c->name == name)
-                       return true; /* already stored */
-               c = c->hashlink;
-       }
-
-       /* check if the name is a valid classname */
-
-       if (!is_valid_name(name->text,UTF_END(name))) {
-               exceptions_throw_classformaterror(pool->referer, "Invalid class name");
-               return false; /* exception */
-       }
-
-       /* XXX check maximum array dimension */
-       
-       c = DNEW(classref_hash_entry);
-       c->name = name;
-       c->index = pool->classrefhash.entries++;
-       c->hashlink = (classref_hash_entry *) pool->classrefhash.ptr[slot];
-       pool->classrefhash.ptr[slot] = c;
-
-       return true;
-}
-
-
-/* descriptor_pool_add *********************************************************
-   Check the given descriptor and add it to the pool
-
-   IN:
-       pool.............the descriptor_pool
-          desc.............the descriptor to add. Maybe a field or method desc.
-
-   OUT:
-       *paramslots......if non-NULL, set to the number of parameters.
-                           LONG and DOUBLE are counted twice
-
-   RETURN VALUE:
-       true.............descriptor has been added
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool 
-descriptor_pool_add(descriptor_pool *pool, utf *desc, int *paramslots)
-{
-       u4 key,slot;
-       descriptor_hash_entry *d;
-       char *utf_ptr;
-       char *end_pos;
-       utf *name;
-       s4 argcount = 0;
-       
-#ifdef DESCRIPTOR_VERBOSE
-       fprintf(stderr,"descriptor_pool_add(%p,",(void*)pool);
-       utf_fprint_printable_ascii(stderr,desc);fprintf(stderr,")\n");
-#endif
-
-       assert(pool);
-       assert(desc);
-
-       /* find a place in the hashtable */
-
-       key = utf_hashkey(desc->text, desc->blength);
-       slot = key & (pool->descriptorhash.size - 1);
-       d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
-
-       /* Save all method descriptors in the hashtable, since the parsed         */
-       /* descriptor may vary between differenf methods (static vs. non-static). */
-
-       utf_ptr = desc->text;
-
-       if (*utf_ptr != '(') {
-               while (d) {
-                       if (d->desc == desc) {
-                               if (paramslots)
-                                       *paramslots = d->paramslots;
-                               return true; /* already stored */
-                       }
-                       d = d->hashlink;
-               }
-       }
-
-       /* add the descriptor to the pool */
-
-       d = DNEW(descriptor_hash_entry);
-       d->desc = desc;
-       d->parseddesc.any = NULL;
-       d->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
-       pool->descriptorhash.ptr[slot] = d;
-
-       /* now check the descriptor */
-
-       end_pos = UTF_END(desc);
-       
-       if (*utf_ptr == '(') {
-               /* a method descriptor */
-
-               pool->methodcount++;
-               utf_ptr++;
-
-               /* check arguments */
-
-               while ((utf_ptr != end_pos) && (*utf_ptr != ')')) {
-                       pool->paramcount++;
-
-                       /* We cannot count the `this' argument here because
-                        * we don't know if the method is static. */
-
-                       if (*utf_ptr == 'J' || *utf_ptr == 'D')
-                               argcount += 2;
-                       else
-                               argcount++;
-
-                       if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, &utf_ptr,
-                                                                     DESCRIPTOR_NOVOID, &name))
-                               return false;
-
-                       if (name)
-                               if (!descriptor_pool_add_class(pool, name))
-                                       return false;
-               }
-
-               if (utf_ptr == end_pos) {
-                       exceptions_throw_classformaterror(pool->referer,
-                                                                                         "Missing ')' in method descriptor");
-                       return false;
-               }
-
-               utf_ptr++; /* skip ')' */
-
-               if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL,
-                                                                 DESCRIPTOR_CHECKEND, &name))
-                       return false;
-
-               if (name)
-                       if (!descriptor_pool_add_class(pool,name))
-                               return false;
-
-               if (argcount > 255) {
-                       exceptions_throw_classformaterror(pool->referer,
-                                                                                         "Too many arguments in signature");
-                       return false;
-               }
-
-       } else {
-               /* a field descriptor */
-
-               pool->fieldcount++;
-               
-           if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL,
-                                                         DESCRIPTOR_NOVOID | DESCRIPTOR_CHECKEND,
-                                                                 &name))
-                       return false;
-
-               if (name)
-                       if (!descriptor_pool_add_class(pool,name))
-                               return false;
-       }
-
-       d->paramslots = argcount;
-
-       if (paramslots)
-               *paramslots = argcount;
-
-       return true;
-}
-
-
-/* descriptor_pool_create_classrefs ********************************************
-   Create a table containing all the classrefs which were added to the pool
-
-   IN:
-       pool.............the descriptor_pool
-
-   OUT:
-       *count...........if count is non-NULL, this is set to the number
-                           of classrefs in the table
-
-   RETURN VALUE:
-       a pointer to the constant_classref table
-
-*******************************************************************************/
-
-constant_classref * 
-descriptor_pool_create_classrefs(descriptor_pool *pool, s4 *count)
-{
-       u4 nclasses;
-       u4 slot;
-       classref_hash_entry *c;
-       constant_classref *ref;
-       
-       assert(pool);
-
-       nclasses = pool->classrefhash.entries;
-       pool->classrefs = MNEW(constant_classref,nclasses);
-
-       /* fill the constant_classref structs */
-
-       for (slot = 0; slot < pool->classrefhash.size; ++slot) {
-               c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
-               while (c) {
-                       ref = pool->classrefs + c->index;
-                       CLASSREF_INIT(*ref, pool->referer, c->name);
-                       c = c->hashlink;
-               }
-       }
-
-       if (count)
-               *count = nclasses;
-
-       return pool->classrefs;
-}
-
-
-/* descriptor_pool_lookup_classref *********************************************
-   Return the constant_classref for the given class name
-
-   IN:
-       pool.............the descriptor_pool
-          classname........name of the class to look up
-
-   RETURN VALUE:
-       a pointer to the constant_classref, or
-          NULL if an exception has been thrown
-
-*******************************************************************************/
-
-constant_classref * 
-descriptor_pool_lookup_classref(descriptor_pool *pool, utf *classname)
-{
-       u4 key,slot;
-       classref_hash_entry *c;
-
-       assert(pool);
-       assert(pool->classrefs);
-       assert(classname);
-
-       key = utf_hashkey(classname->text, classname->blength);
-       slot = key & (pool->classrefhash.size - 1);
-       c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
-
-       while (c) {
-               if (c->name == classname)
-                       return pool->classrefs + c->index;
-               c = c->hashlink;
-       }
-
-       exceptions_throw_internalerror("Class reference not found in descriptor pool");
-       return NULL;
-}
-
-
-/* descriptor_pool_alloc_parsed_descriptors ************************************
-   Allocate space for the parsed descriptors
-
-   IN:
-       pool.............the descriptor_pool
-
-   NOTE:
-       This function must be called after all descriptors have been added
-          with descriptor_pool_add.
-
-*******************************************************************************/
-
-void 
-descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool)
-{
-       u4 size;
-       
-       assert(pool);
-
-       /* TWISTI: paramcount + 1: we don't know if the method is static or   */
-       /* not, i have no better solution yet.                                */
-
-       size =
-               pool->fieldcount * sizeof(typedesc) +
-               pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc)) +
-               pool->paramcount * sizeof(typedesc) +
-               pool->methodcount * sizeof(typedesc);      /* possible `this' pointer */
-
-       pool->descriptorsize = size;
-       if (size) {
-               pool->descriptors = MNEW(u1, size);
-               pool->descriptors_next = pool->descriptors;
-       }
-
-       size = pool->fieldcount + pool->methodcount;
-       if (size) {
-               pool->descriptor_kind = DMNEW(u1, size);
-               pool->descriptor_kind_next = pool->descriptor_kind;
-       }
-}
-
-
-/* descriptor_pool_parse_field_descriptor **************************************
-   Parse the given field descriptor
-
-   IN:
-       pool.............the descriptor_pool
-          desc.............the field descriptor
-
-   RETURN VALUE:
-       a pointer to the parsed field descriptor, or
-          NULL if an exception has been thrown
-
-   NOTE:
-       descriptor_pool_alloc_parsed_descriptors must be called (once)
-       before this function is used.
-
-*******************************************************************************/
-
-typedesc * 
-descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc)
-{
-       u4 key,slot;
-       descriptor_hash_entry *d;
-       typedesc *td;
-
-       assert(pool);
-       assert(pool->descriptors);
-       assert(pool->descriptors_next);
-
-       /* lookup the descriptor in the hashtable */
-
-       key = utf_hashkey(desc->text, desc->blength);
-       slot = key & (pool->descriptorhash.size - 1);
-       d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
-
-       while (d) {
-               if (d->desc == desc) {
-                       /* found */
-                       if (d->parseddesc.fd)
-                               return d->parseddesc.fd;
-                       break;
-               }
-               d = d->hashlink;
-       }
-
-       assert(d);
-       
-       if (desc->text[0] == '(') {
-               exceptions_throw_classformaterror(pool->referer,
-                                                                                 "Method descriptor used in field reference");
-               return NULL;
-       }
-
-       td = (typedesc *) pool->descriptors_next;
-       pool->descriptors_next += sizeof(typedesc);
-       
-       if (!descriptor_to_typedesc(pool, desc->text, UTF_END(desc), NULL, td))
-               return NULL;
-
-       *(pool->descriptor_kind_next++) = 'f';
-
-       d->parseddesc.fd = td;
-
-       return td;
-}
-
-
-/* descriptor_pool_parse_method_descriptor *************************************
-   Parse the given method descriptor
-
-   IN:
-       pool.............the descriptor_pool
-       desc.............the method descriptor
-       mflags...........the method flags
-          thisclass........classref to the class containing the method.
-                                               This is ignored if mflags contains ACC_STATIC.
-                                               The classref is stored for inserting the 'this' argument.
-
-   RETURN VALUE:
-       a pointer to the parsed method descriptor, or
-          NULL if an exception has been thrown
-
-   NOTE: 
-       descriptor_pool_alloc_parsed_descriptors must be called
-       (once) before this function is used.
-
-*******************************************************************************/
-
-methoddesc * 
-descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc,
-                                                                               s4 mflags,constant_classref *thisclass)
-{
-       u4 key, slot;
-       descriptor_hash_entry *d;
-       methoddesc            *md;
-       typedesc              *td;
-       char *utf_ptr;
-       char *end_pos;
-       s2 paramcount = 0;
-       s2 paramslots = 0;
-
-#ifdef DESCRIPTOR_VERBOSE
-       fprintf(stderr,"descriptor_pool_parse_method_descriptor(%p,%d,%p,",
-                       (void*)pool,(int)mflags,(void*)thisclass);
-       utf_fprint_printable_ascii(stderr,desc); fprintf(stderr,")\n");
-#endif
-
-       assert(pool);
-       assert(pool->descriptors);
-       assert(pool->descriptors_next);
-
-       /* check that it is a method descriptor */
-       
-       if (desc->text[0] != '(') {
-               exceptions_throw_classformaterror(pool->referer,
-                                                                                 "Field descriptor used in method reference");
-               return NULL;
-       }
-
-       /* lookup the descriptor in the hashtable */
-
-       key = utf_hashkey(desc->text, desc->blength);
-       slot = key & (pool->descriptorhash.size - 1);
-       d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
-
-       /* find an un-parsed descriptor */
-
-       while (d) {
-               if (d->desc == desc)
-                       if (!d->parseddesc.md)
-                               break;
-               d = d->hashlink;
-       }
-
-       assert(d);
-
-       md = (methoddesc *) pool->descriptors_next;
-       pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc);
-
-       utf_ptr = desc->text + 1; /* skip '(' */
-       end_pos = UTF_END(desc);
-
-       td = md->paramtypes;
-
-       /* count the `this' pointer */
-
-       if ((mflags != ACC_UNDEF) && !(mflags & ACC_STATIC)) {
-               td->type = TYPE_ADR;
-               td->primitivetype = TYPE_ADR;
-               td->arraydim = 0;
-               td->classref = thisclass;
-
-               td++;
-               pool->descriptors_next += sizeof(typedesc);
-               paramcount++;
-               paramslots++;
-       }
-
-       while (*utf_ptr != ')') {
-               /* parse a parameter type */
-
-               if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, &utf_ptr, td))
-                       return NULL;
-
-               if (IS_2_WORD_TYPE(td->type))
-                       paramslots++;
-               
-               td++;
-               pool->descriptors_next += sizeof(typedesc);
-               paramcount++;
-               paramslots++;
-       }
-       utf_ptr++; /* skip ')' */
-
-       /* Skip possible `this' pointer in paramtypes array to allow a possible   */
-       /* memory move later in parse.                                            */
-       /* We store the thisclass reference, so we can later correctly fill in    */
-       /* the parameter slot of the 'this' argument.                             */
-
-       if (mflags == ACC_UNDEF) {
-               td->classref = thisclass;
-               td++;
-               pool->descriptors_next += sizeof(typedesc);
-       }
-
-       /* parse return type */
-
-       if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, NULL,
-                                                               &(md->returntype)))
-               return NULL;
-
-       md->paramcount = paramcount;
-       md->paramslots = paramslots;
-
-       /* If mflags != ACC_UNDEF we parse a real loaded method, so do
-          param prealloc.  Otherwise we do this in stack analysis. */
-
-       if (mflags != ACC_UNDEF) {
-               if (md->paramcount > 0) {
-                       /* allocate memory for params */
-
-                       md->params = MNEW(paramdesc, md->paramcount);
-               }
-               else {
-                       md->params = METHODDESC_NOPARAMS;
-               }
-
-               /* fill the paramdesc */
-               /* md_param_alloc has to be called if md->paramcount == 0,
-                  too, so it can make the reservation for the Linkage Area,
-                  Return Register... */
-
-#if defined(ENABLE_JIT)
-# if defined(ENABLE_INTRP)
-               if (!opt_intrp)
-# endif
-                       {
-                               /* As builtin-functions are native functions, we have
-                                  to pre-allocate for the native ABI. */
-
-                               if (mflags & ACC_METHOD_BUILTIN)
-                                       md_param_alloc_native(md);
-                               else
-                                       md_param_alloc(md);
-                       }
-#endif
-       }
-       else {
-               /* params will be allocated later by
-                  descriptor_params_from_paramtypes if necessary */
-
-               md->params = NULL;
-       }
-
-       *(pool->descriptor_kind_next++) = 'm';
-
-       d->parseddesc.md = md;
-
-       return md;
-}
-
-/* descriptor_params_from_paramtypes *******************************************
-   Create the paramdescs for a method descriptor. This function is called
-   when we know whether the method is static or not. This function may only
-   be called once for each methoddesc, and only if md->params == NULL.
-
-   IN:
-       md...............the parsed method descriptor
-                           md->params MUST be NULL.
-          mflags...........the ACC_* access flags of the method. Only the
-                           ACC_STATIC bit is checked.
-                                               The value ACC_UNDEF is NOT allowed.
-
-   RETURN VALUE:
-       true.............the paramdescs were created successfully
-          false............an exception has been thrown
-
-   POSTCONDITION:
-       md->parms != NULL
-
-*******************************************************************************/
-
-bool descriptor_params_from_paramtypes(methoddesc *md, s4 mflags)
-{
-       typedesc *td;
-
-       assert(md);
-       assert(md->params == NULL);
-       assert(mflags != ACC_UNDEF);
-
-       td = md->paramtypes;
-
-       /* check for `this' pointer */
-
-       if (!(mflags & ACC_STATIC)) {
-               constant_classref *thisclass;
-
-               /* fetch class reference from reserved param slot */
-               thisclass = td[md->paramcount].classref;
-               assert(thisclass);
-
-               if (md->paramcount > 0) {
-                       /* shift param types by 1 argument */
-                       MMOVE(td + 1, td, typedesc, md->paramcount);
-               }
-
-               /* fill in first argument `this' */
-
-               td->type = TYPE_ADR;
-               td->primitivetype = TYPE_ADR;
-               td->arraydim = 0;
-               td->classref = thisclass;
-
-               md->paramcount++;
-               md->paramslots++;
-       }
-
-       /* if the method has params, process them */
-
-       if (md->paramcount > 0) {
-               /* allocate memory for params */
-
-               md->params = MNEW(paramdesc, md->paramcount);
-
-       } else {
-               md->params = METHODDESC_NOPARAMS;
-       }
-
-       /* fill the paramdesc */
-       /* md_param_alloc has to be called if md->paramcount == 0, too, so
-          it can make the reservation for the Linkage Area, Return
-          Register.. */
-
-#if defined(ENABLE_JIT)
-# if defined(ENABLE_INTRP)
-       if (!opt_intrp)
-# endif
-               {
-                       /* As builtin-functions are native functions, we have to
-                          pre-allocate for the native ABI. */
-
-                       if (mflags & ACC_METHOD_BUILTIN)
-                               md_param_alloc_native(md);
-                       else
-                               md_param_alloc(md);
-               }
-#endif
-
-       return true;
-}
-
-
-/* descriptor_pool_get_parsed_descriptors **************************************
-   Return a pointer to the block of parsed descriptors
-
-   IN:
-       pool.............the descriptor_pool
-
-   OUT:
-          *size............if size is non-NULL, this is set to the size of the
-                           parsed descriptor block (in u1)
-
-   RETURN VALUE:
-       a pointer to the block of parsed descriptors
-
-   NOTE:
-       descriptor_pool_alloc_parsed_descriptors must be called (once)
-       before this function is used.
-
-*******************************************************************************/
-
-void * 
-descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size)
-{
-       assert(pool);
-       assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
-       
-       if (size)
-               *size = pool->descriptorsize;
-
-       return pool->descriptors;
-}
-
-
-/* descriptor_pool_get_sizes ***************************************************
-   Get the sizes of the class reference table and the parsed descriptors
-
-   IN:
-       pool.............the descriptor_pool
-
-   OUT:
-       *classrefsize....set to size of the class reference table
-          *descsize........set to size of the parsed descriptors
-
-   NOTE:
-       This function may only be called after both
-              descriptor_pool_create_classrefs, and
-                  descriptor_pool_alloc_parsed_descriptors
-          have been called.
-
-*******************************************************************************/
-
-void 
-descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize, u4 *descsize)
-{
-       assert(pool);
-       assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
-       assert(pool->classrefs);
-       assert(classrefsize);
-       assert(descsize);
-
-       *classrefsize = pool->classrefhash.entries * sizeof(constant_classref);
-       *descsize = pool->descriptorsize;
-}
-
-
-/****************************************************************************/
-/* DEBUG HELPERS                                                            */
-/****************************************************************************/
-
-#ifndef NDEBUG
-/* descriptor_debug_print_typedesc *********************************************
-   Print the given typedesc to the given stream
-
-   IN:
-          file.............stream to print to
-          d................the parsed descriptor
-
-*******************************************************************************/
-
-void 
-descriptor_debug_print_typedesc(FILE *file,typedesc *d)
-{
-       int ch;
-
-       if (!d) {
-               fprintf(file,"(typedesc *)NULL");
-               return;
-       }
-       
-       if (d->type == TYPE_ADR) {
-               if (d->classref)
-                       utf_fprint_printable_ascii(file,d->classref->name);
-               else
-                       fprintf(file,"<class=NULL>");
-       }
-       else {
-               switch (d->primitivetype) {
-                       case PRIMITIVETYPE_INT    : ch='I'; break;
-                       case PRIMITIVETYPE_CHAR   : ch='C'; break;
-                       case PRIMITIVETYPE_BYTE   : ch='B'; break;
-                       case PRIMITIVETYPE_SHORT  : ch='S'; break;
-                       case PRIMITIVETYPE_BOOLEAN: ch='Z'; break;
-                       case PRIMITIVETYPE_LONG   : ch='J'; break;
-                       case PRIMITIVETYPE_FLOAT  : ch='F'; break;
-                       case PRIMITIVETYPE_DOUBLE : ch='D'; break;
-                       case PRIMITIVETYPE_VOID   : ch='V'; break;
-                       default                   : ch='!';
-               }
-               fputc(ch,file);
-       }
-       if (d->arraydim)
-               fprintf(file,"[%d]",d->arraydim);
-}
-
-/* descriptor_debug_print_paramdesc ********************************************
-   Print the given paramdesc to the given stream
-
-   IN:
-          file.............stream to print to
-          d................the parameter descriptor
-
-*******************************************************************************/
-
-void
-descriptor_debug_print_paramdesc(FILE *file,paramdesc *d)
-{
-       if (!d) {
-               fprintf(file,"(paramdesc *)NULL");
-               return;
-       }
-       
-       if (d->inmemory) {
-               fprintf(file,"<m%d>",d->regoff);
-       }
-       else {
-               fprintf(file,"<r%d>",d->regoff);
-       }
-}
-
-/* descriptor_debug_print_methoddesc *******************************************
-   Print the given methoddesc to the given stream
-
-   IN:
-          file.............stream to print to
-          d................the parsed descriptor
-
-*******************************************************************************/
-
-void 
-descriptor_debug_print_methoddesc(FILE *file,methoddesc *d)
-{
-       int i;
-       
-       if (!d) {
-               fprintf(file,"(methoddesc *)NULL");
-               return;
-       }
-       
-       fputc('(',file);
-       for (i=0; i<d->paramcount; ++i) {
-               if (i)
-                       fputc(',',file);
-               descriptor_debug_print_typedesc(file,d->paramtypes + i);
-               if (d->params) {
-                       descriptor_debug_print_paramdesc(file,d->params + i);
-               }
-       }
-       if (d->params == METHODDESC_NOPARAMS)
-               fputs("<NOPARAMS>",file);
-       fputc(')',file);
-       descriptor_debug_print_typedesc(file,&(d->returntype));
-}
-
-/* descriptor_pool_debug_dump **************************************************
-   Print the state of the descriptor_pool to the given stream
-
-   IN:
-       pool.............the descriptor_pool
-          file.............stream to print to
-
-*******************************************************************************/
-
-void 
-descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file)
-{
-       u4 slot;
-       u1 *pos;
-       u1 *kind;
-       u4 size;
-       
-       fprintf(file,"======[descriptor_pool for ");
-       utf_fprint_printable_ascii(file,pool->referer->name);
-       fprintf(file,"]======\n");
-
-       fprintf(file,"fieldcount:     %d\n",pool->fieldcount);
-       fprintf(file,"methodcount:    %d\n",pool->methodcount);
-       fprintf(file,"paramcount:     %d\n",pool->paramcount);
-       fprintf(file,"classrefcount:  %d\n",pool->classrefhash.entries);
-       fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize);
-       fprintf(file,"classrefsize:   %d bytes\n",
-                       (int)(pool->classrefhash.entries * sizeof(constant_classref)));
-
-       fprintf(file,"class references:\n");
-       for (slot=0; slot<pool->classrefhash.size; ++slot) {
-               classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
-               while (c) {
-                       fprintf(file,"    %4d: ",c->index);
-                       utf_fprint_printable_ascii(file,c->name);
-                       fprintf(file,"\n");
-                       c = c->hashlink;
-               }
-       }
-
-       fprintf(file,"hashed descriptors:\n");
-       for (slot=0; slot<pool->descriptorhash.size; ++slot) {
-               descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
-               while (c) {
-                       fprintf(file,"    %p: ",c->parseddesc.any);
-                       utf_fprint_printable_ascii(file,c->desc);
-                       fprintf(file,"\n");
-                       c = c->hashlink;
-               }
-       }
-
-       fprintf(file,"descriptors:\n");
-       if (pool->descriptors) {
-               pos = pool->descriptors;
-               size = pool->descriptors_next - pool->descriptors;
-               fprintf(file,"    size: %d bytes\n",size);
-               
-               if (pool->descriptor_kind) {
-                       kind = pool->descriptor_kind;
-
-                       while (pos < (pool->descriptors + size)) {
-                               fprintf(file,"    %p: ",pos);
-                               switch (*kind++) {
-                                       case 'f':
-                                               descriptor_debug_print_typedesc(file,(typedesc*)pos);
-                                               pos += sizeof(typedesc);
-                                               break;
-                                       case 'm':
-                                               descriptor_debug_print_methoddesc(file,(methoddesc*)pos);
-                                               pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc);
-                                               pos += sizeof(methoddesc) - sizeof(typedesc);
-                                               break;
-                                       default:
-                                               fprintf(file,"INVALID KIND");
-                               }
-                               fputc('\n',file);
-                       }
-               }
-               else {
-                       while (size >= sizeof(void*)) {
-                               fprintf(file,"    %p\n",*((void**)pos));
-                               pos += sizeof(void*);
-                               size -= sizeof(void*);
-                       }
-               }
-       }
-
-       fprintf(file,"==========================================================\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/descriptor.cpp b/src/vm/descriptor.cpp
new file mode 100644 (file)
index 0000000..f939c60
--- /dev/null
@@ -0,0 +1,1406 @@
+/* src/vm/descriptor.c - checking and parsing of field / method descriptors
+
+   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 "md-abi.h"
+
+#include "mm/memory.h"
+
+#include "vm/descriptor.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/options.h"
+#include "vm/primitive.hpp"
+#include "vm/vm.hpp"
+
+#include "vm/jit/abi.h"
+
+
+/* constants (private to descriptor.c) ****************************************/
+
+/* initial number of entries for the classrefhash of a descriptor_pool */
+/* (currently the hash is never grown!) */
+#define CLASSREFHASH_INIT_SIZE  64
+
+/* initial number of entries for the descriptorhash of a descriptor_pool */
+/* (currently the hash is never grown!) */
+#define DESCRIPTORHASH_INIT_SIZE  128
+
+/* data structures (private to descriptor.c) **********************************/
+
+typedef struct classref_hash_entry classref_hash_entry;
+typedef struct descriptor_hash_entry descriptor_hash_entry;
+
+/* entry struct for the classrefhash of descriptor_pool */
+struct classref_hash_entry {
+       classref_hash_entry *hashlink;  /* for hash chaining            */
+       utf                 *name;      /* name of the class refered to */
+       u2                   index;     /* index into classref table    */
+};
+
+/* entry struct for the descriptorhash of descriptor_pool */
+struct descriptor_hash_entry {
+       descriptor_hash_entry *hashlink;
+       utf                   *desc;
+       parseddesc_t           parseddesc;
+       s2                     paramslots; /* number of params, LONG/DOUBLE counted as 2 */
+};
+
+
+/****************************************************************************/
+/* MACROS FOR DESCRIPTOR PARSING (private to descriptor.c)                  */
+/****************************************************************************/
+
+/* SKIP_FIELDDESCRIPTOR:
+ * utf_ptr must point to the first character of a field descriptor.
+ * After the macro call utf_ptr points to the first character after
+ * the field descriptor.
+ *
+ * CAUTION: This macro does not check for an unexpected end of the
+ * descriptor. Better use SKIP_FIELDDESCRIPTOR_SAFE.
+ */
+#define SKIP_FIELDDESCRIPTOR(utf_ptr)                                                  \
+       do { while (*(utf_ptr)=='[') (utf_ptr)++;                                       \
+               if (*(utf_ptr)++=='L')                                                                  \
+                       while(*(utf_ptr)++ != ';') /* skip */; } while(0)
+
+/* SKIP_FIELDDESCRIPTOR_SAFE:
+ * utf_ptr must point to the first character of a field descriptor.
+ * After the macro call utf_ptr points to the first character after
+ * the field descriptor.
+ *
+ * Input:
+ *     utf_ptr....points to first char of descriptor
+ *     end_ptr....points to first char after the end of the string
+ *     errorflag..must be initialized (to false) by the caller!
+ * Output:
+ *     utf_ptr....points to first char after the descriptor
+ *     errorflag..set to true if the string ended unexpectedly
+ */
+#define SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,errorflag)                   \
+       do { while ((utf_ptr) != (end_ptr) && *(utf_ptr)=='[') (utf_ptr)++;     \
+               if ((utf_ptr) == (end_ptr))                                                                             \
+                       (errorflag) = true;                                                                                     \
+               else                                                                                                                    \
+                       if (*(utf_ptr)++=='L') {                                                                        \
+                               while((utf_ptr) != (end_ptr) && *(utf_ptr)++ != ';')    \
+                                       /* skip */;                                                                                     \
+                               if ((utf_ptr)[-1] != ';')                                                               \
+                                       (errorflag) = true; }} while(0)
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/****************************************************************************/
+/* DEBUG HELPERS                                                            */
+/****************************************************************************/
+
+/*#define DESCRIPTOR_VERBOSE*/
+
+/****************************************************************************/
+/* FUNCTIONS                                                                */
+/****************************************************************************/
+
+/* descriptor_to_basic_type ****************************************************
+
+   Return the basic type to use for a value with this descriptor.
+
+   IN:
+       utf..............descriptor utf string
+
+   OUT:
+       A TYPE_* constant.
+
+   PRECONDITIONS:
+       This function assumes that the descriptor has passed 
+          descriptor_pool_add checks and that it does not start with '('.
+
+*******************************************************************************/
+
+int descriptor_to_basic_type(utf *descriptor)
+{
+       assert(descriptor->blength >= 1);
+       
+       switch (descriptor->text[0]) {
+       case 'Z':
+       case 'B':
+       case 'C':
+       case 'S':
+       case 'I':
+               return TYPE_INT;
+
+       case 'J':
+               return TYPE_LNG;
+
+       case 'F':
+               return TYPE_FLT;
+
+       case 'D':
+               return TYPE_DBL;
+
+       case 'L':
+       case '[':
+               return TYPE_ADR;
+
+       default:
+               vm_abort("descriptor_to_basic_type: invalid type %c",
+                                descriptor->text[0]);
+       }
+
+       /* keep the compiler happy */
+
+       return 0;
+}
+
+
+/* descriptor_typesize *********************************************************
+
+   Return the size in bytes needed for the given type.
+
+   IN:
+       td..............typedesc describing the type
+
+   OUT:
+       The number of bytes
+
+*******************************************************************************/
+
+int descriptor_typesize(typedesc *td)
+{
+       assert(td);
+
+       switch (td->type) {
+       case TYPE_INT:
+       case TYPE_FLT:
+               return 4;
+
+       case TYPE_LNG:
+       case TYPE_DBL:
+               return 8;
+
+       case TYPE_ADR:
+               return SIZEOF_VOID_P;
+
+       default:
+               vm_abort("descriptor_typesize: invalid type %d", td->type);
+       }
+
+       /* keep the compiler happy */
+
+       return 0;
+}
+
+
+/* name_from_descriptor ********************************************************
+
+   Return the class name indicated by the given descriptor
+   (Internally used helper function)
+
+   IN:
+       c................class containing the descriptor
+       utf_ptr..........first character of descriptor
+       end_ptr..........first character after the end of the string
+       mode.............a combination (binary or) of the following flags:
+
+               (Flags marked with * are the default settings.)
+
+               How to handle "V" descriptors:
+
+                            * DESCRIPTOR_VOID.....handle it like other primitive types
+                   DESCRIPTOR_NOVOID...treat it as an error
+
+               How to deal with extra characters after the end of the
+               descriptor:
+
+                            * DESCRIPTOR_NOCHECKEND...ignore (useful for parameter lists)
+                   DESCRIPTOR_CHECKEND.....treat them as an error
+
+   OUT:
+       *next............if non-NULL, *next is set to the first character after
+                        the descriptor. (Undefined if an error occurs.)
+       *name............set to the utf name of the class
+
+   RETURN VALUE:
+       true.............descriptor parsed successfully
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+#define DESCRIPTOR_VOID          0      /* default */
+#define DESCRIPTOR_NOVOID        0x0040
+#define DESCRIPTOR_NOCHECKEND    0      /* default */
+#define DESCRIPTOR_CHECKEND      0x1000
+
+static bool 
+name_from_descriptor(classinfo *c,
+                                        char *utf_ptr, char *end_ptr,
+                                        char **next, int mode, utf **name)
+{
+       char *start = utf_ptr;
+       bool error = false;
+
+       assert(c);
+       assert(utf_ptr);
+       assert(end_ptr);
+       assert(name);
+       
+       *name = NULL;           
+       SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error);
+
+       if (mode & DESCRIPTOR_CHECKEND)
+               error |= (utf_ptr != end_ptr);
+       
+       if (!error) {
+               if (next) *next = utf_ptr;
+               
+               switch (*start) {
+                 case 'V':
+                         if (mode & DESCRIPTOR_NOVOID)
+                                 break;
+                         /* FALLTHROUGH! */
+                 case 'I':
+                 case 'J':
+                 case 'F':
+                 case 'D':
+                 case 'B':
+                 case 'C':
+                 case 'S':
+                 case 'Z':
+                         return true;
+                         
+                 case 'L':
+                         start++;
+                         utf_ptr--;
+                         /* FALLTHROUGH! */
+                 case '[':
+                         *name = utf_new(start, utf_ptr - start);
+                         return true;
+               }
+       }
+
+       exceptions_throw_classformaterror(c, "Invalid descriptor");
+       return false;
+}
+
+
+/* descriptor_to_typedesc ******************************************************
+   Parse the given type descriptor and fill a typedesc struct
+   (Internally used helper function)
+
+   IN:
+       pool.............the descriptor pool
+          utf_ptr..........points to first character of type descriptor
+          end_pos..........points after last character of the whole descriptor
+
+   OUT:
+       *next............set to next character after type descriptor
+          *d...............filled with parsed information
+
+   RETURN VALUE:
+       true.............parsing succeeded  
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+static bool
+descriptor_to_typedesc(descriptor_pool *pool, char *utf_ptr, char *end_pos,
+                                          char **next, typedesc *td)
+{
+       utf *name;
+       
+       if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, next, 0, &name))
+               return false;
+
+       if (name) {
+               /* a reference type */
+               td->type = TYPE_ADR;
+               td->primitivetype = TYPE_ADR;
+               td->arraydim = 0;
+               for (utf_ptr = name->text; *utf_ptr == '['; ++utf_ptr)
+                       td->arraydim++;
+               td->classref = descriptor_pool_lookup_classref(pool, name);
+
+       } else {
+               /* a primitive type */
+               switch (*utf_ptr) {
+               case 'B': 
+                       td->primitivetype = PRIMITIVETYPE_BYTE;
+                       td->type = TYPE_INT;
+                       break;
+               case 'C':
+                       td->primitivetype = PRIMITIVETYPE_CHAR;
+                       td->type = TYPE_INT;
+                       break;
+               case 'S':  
+                       td->primitivetype = PRIMITIVETYPE_SHORT;
+                       td->type = TYPE_INT;
+                       break;
+               case 'Z':
+                       td->primitivetype = PRIMITIVETYPE_BOOLEAN;
+                       td->type = TYPE_INT;
+                       break;
+               case 'I':
+                       td->primitivetype = PRIMITIVETYPE_INT;
+                       td->type = TYPE_INT;
+                       break;
+               case 'D':
+                       td->primitivetype = PRIMITIVETYPE_DOUBLE;
+                       td->type = TYPE_DBL;
+                       break;
+               case 'F':
+                       td->primitivetype = PRIMITIVETYPE_FLOAT;
+                       td->type = TYPE_FLT;
+                       break;
+               case 'J':
+                       td->primitivetype = PRIMITIVETYPE_LONG;
+                       td->type = TYPE_LNG;
+                       break;
+               case 'V':
+                       td->primitivetype = PRIMITIVETYPE_VOID;
+                       td->type = TYPE_VOID;
+                       break;
+               default:
+                       assert(false);
+               }
+
+               td->arraydim = 0;
+               td->classref = NULL;
+       }
+
+       return true;
+}
+
+
+/* descriptor_pool_new *********************************************************
+   Allocate a new descriptor_pool
+
+   IN:
+       referer..........class for which to create the pool
+
+   RETURN VALUE:
+       a pointer to the new descriptor_pool
+
+*******************************************************************************/
+
+descriptor_pool * 
+descriptor_pool_new(classinfo *referer)
+{
+       descriptor_pool *pool;
+       u4 hashsize;
+       u4 slot;
+
+       pool = (descriptor_pool*) DumpMemory::allocate(sizeof(descriptor_pool));
+       assert(pool);
+
+       pool->referer = referer;
+       pool->fieldcount = 0;
+       pool->methodcount = 0;
+       pool->paramcount = 0;
+       pool->descriptorsize = 0;
+       pool->descriptors = NULL;
+       pool->descriptors_next = NULL;
+       pool->classrefs = NULL;
+       pool->descriptor_kind = NULL;
+       pool->descriptor_kind_next = NULL;
+
+       hashsize = CLASSREFHASH_INIT_SIZE;
+       pool->classrefhash.size = hashsize;
+       pool->classrefhash.entries = 0;
+       pool->classrefhash.ptr = (void **) DumpMemory::allocate(sizeof(void*) * hashsize);
+       for (slot=0; slot<hashsize; ++slot)
+               pool->classrefhash.ptr[slot] = NULL;
+
+       hashsize = DESCRIPTORHASH_INIT_SIZE;
+       pool->descriptorhash.size = hashsize;
+       pool->descriptorhash.entries = 0;
+       pool->descriptorhash.ptr = (void**) DumpMemory::allocate(sizeof(void*) * hashsize);
+       for (slot=0; slot<hashsize; ++slot)
+               pool->descriptorhash.ptr[slot] = NULL;
+
+       return pool;
+}
+
+
+/* descriptor_pool_add_class ***************************************************
+   Add the given class reference to the pool
+
+   IN:
+       pool.............the descriptor_pool
+          name.............the class reference to add
+
+   RETURN VALUE:
+       true.............reference has been added
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool 
+descriptor_pool_add_class(descriptor_pool *pool, utf *name)
+{
+       u4 key,slot;
+       classref_hash_entry *c;
+       
+       assert(pool);
+       assert(name);
+
+#ifdef DESCRIPTOR_VERBOSE
+       fprintf(stderr,"descriptor_pool_add_class(%p,",(void*)pool);
+       utf_fprint_printable_ascii(stderr,name);fprintf(stderr,")\n");
+#endif
+
+       /* find a place in the hashtable */
+
+       key = utf_hashkey(name->text, name->blength);
+       slot = key & (pool->classrefhash.size - 1);
+       c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
+
+       while (c) {
+               if (c->name == name)
+                       return true; /* already stored */
+               c = c->hashlink;
+       }
+
+       /* check if the name is a valid classname */
+
+       if (!is_valid_name(name->text,UTF_END(name))) {
+               exceptions_throw_classformaterror(pool->referer, "Invalid class name");
+               return false; /* exception */
+       }
+
+       /* XXX check maximum array dimension */
+       
+       c = (classref_hash_entry*) DumpMemory::allocate(sizeof(classref_hash_entry));
+       c->name = name;
+       c->index = pool->classrefhash.entries++;
+       c->hashlink = (classref_hash_entry *) pool->classrefhash.ptr[slot];
+       pool->classrefhash.ptr[slot] = c;
+
+       return true;
+}
+
+
+/* descriptor_pool_add *********************************************************
+   Check the given descriptor and add it to the pool
+
+   IN:
+       pool.............the descriptor_pool
+          desc.............the descriptor to add. Maybe a field or method desc.
+
+   OUT:
+       *paramslots......if non-NULL, set to the number of parameters.
+                           LONG and DOUBLE are counted twice
+
+   RETURN VALUE:
+       true.............descriptor has been added
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool 
+descriptor_pool_add(descriptor_pool *pool, utf *desc, int *paramslots)
+{
+       u4 key,slot;
+       descriptor_hash_entry *d;
+       char *utf_ptr;
+       char *end_pos;
+       utf *name;
+       s4 argcount = 0;
+       
+#ifdef DESCRIPTOR_VERBOSE
+       fprintf(stderr,"descriptor_pool_add(%p,",(void*)pool);
+       utf_fprint_printable_ascii(stderr,desc);fprintf(stderr,")\n");
+#endif
+
+       assert(pool);
+       assert(desc);
+
+       /* find a place in the hashtable */
+
+       key = utf_hashkey(desc->text, desc->blength);
+       slot = key & (pool->descriptorhash.size - 1);
+       d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
+
+       /* Save all method descriptors in the hashtable, since the parsed         */
+       /* descriptor may vary between differenf methods (static vs. non-static). */
+
+       utf_ptr = desc->text;
+
+       if (*utf_ptr != '(') {
+               while (d) {
+                       if (d->desc == desc) {
+                               if (paramslots)
+                                       *paramslots = d->paramslots;
+                               return true; /* already stored */
+                       }
+                       d = d->hashlink;
+               }
+       }
+
+       /* add the descriptor to the pool */
+
+       d = (descriptor_hash_entry*) DumpMemory::allocate(sizeof(descriptor_hash_entry));
+       d->desc = desc;
+       d->parseddesc.any = NULL;
+       d->hashlink = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
+       pool->descriptorhash.ptr[slot] = d;
+
+       /* now check the descriptor */
+
+       end_pos = UTF_END(desc);
+       
+       if (*utf_ptr == '(') {
+               /* a method descriptor */
+
+               pool->methodcount++;
+               utf_ptr++;
+
+               /* check arguments */
+
+               while ((utf_ptr != end_pos) && (*utf_ptr != ')')) {
+                       pool->paramcount++;
+
+                       /* We cannot count the `this' argument here because
+                        * we don't know if the method is static. */
+
+                       if (*utf_ptr == 'J' || *utf_ptr == 'D')
+                               argcount += 2;
+                       else
+                               argcount++;
+
+                       if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, &utf_ptr,
+                                                                     DESCRIPTOR_NOVOID, &name))
+                               return false;
+
+                       if (name)
+                               if (!descriptor_pool_add_class(pool, name))
+                                       return false;
+               }
+
+               if (utf_ptr == end_pos) {
+                       exceptions_throw_classformaterror(pool->referer,
+                                                                                         "Missing ')' in method descriptor");
+                       return false;
+               }
+
+               utf_ptr++; /* skip ')' */
+
+               if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL,
+                                                                 DESCRIPTOR_CHECKEND, &name))
+                       return false;
+
+               if (name)
+                       if (!descriptor_pool_add_class(pool,name))
+                               return false;
+
+               if (argcount > 255) {
+                       exceptions_throw_classformaterror(pool->referer,
+                                                                                         "Too many arguments in signature");
+                       return false;
+               }
+
+       } else {
+               /* a field descriptor */
+
+               pool->fieldcount++;
+               
+           if (!name_from_descriptor(pool->referer, utf_ptr, end_pos, NULL,
+                                                         DESCRIPTOR_NOVOID | DESCRIPTOR_CHECKEND,
+                                                                 &name))
+                       return false;
+
+               if (name)
+                       if (!descriptor_pool_add_class(pool,name))
+                               return false;
+       }
+
+       d->paramslots = argcount;
+
+       if (paramslots)
+               *paramslots = argcount;
+
+       return true;
+}
+
+
+/* descriptor_pool_create_classrefs ********************************************
+   Create a table containing all the classrefs which were added to the pool
+
+   IN:
+       pool.............the descriptor_pool
+
+   OUT:
+       *count...........if count is non-NULL, this is set to the number
+                           of classrefs in the table
+
+   RETURN VALUE:
+       a pointer to the constant_classref table
+
+*******************************************************************************/
+
+constant_classref * 
+descriptor_pool_create_classrefs(descriptor_pool *pool, s4 *count)
+{
+       u4 nclasses;
+       u4 slot;
+       classref_hash_entry *c;
+       constant_classref *ref;
+       
+       assert(pool);
+
+       nclasses = pool->classrefhash.entries;
+       pool->classrefs = MNEW(constant_classref,nclasses);
+
+       /* fill the constant_classref structs */
+
+       for (slot = 0; slot < pool->classrefhash.size; ++slot) {
+               c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
+               while (c) {
+                       ref = pool->classrefs + c->index;
+                       CLASSREF_INIT(*ref, pool->referer, c->name);
+                       c = c->hashlink;
+               }
+       }
+
+       if (count)
+               *count = nclasses;
+
+       return pool->classrefs;
+}
+
+
+/* descriptor_pool_lookup_classref *********************************************
+   Return the constant_classref for the given class name
+
+   IN:
+       pool.............the descriptor_pool
+          classname........name of the class to look up
+
+   RETURN VALUE:
+       a pointer to the constant_classref, or
+          NULL if an exception has been thrown
+
+*******************************************************************************/
+
+constant_classref * 
+descriptor_pool_lookup_classref(descriptor_pool *pool, utf *classname)
+{
+       u4 key,slot;
+       classref_hash_entry *c;
+
+       assert(pool);
+       assert(pool->classrefs);
+       assert(classname);
+
+       key = utf_hashkey(classname->text, classname->blength);
+       slot = key & (pool->classrefhash.size - 1);
+       c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
+
+       while (c) {
+               if (c->name == classname)
+                       return pool->classrefs + c->index;
+               c = c->hashlink;
+       }
+
+       exceptions_throw_internalerror("Class reference not found in descriptor pool");
+       return NULL;
+}
+
+
+/* descriptor_pool_alloc_parsed_descriptors ************************************
+   Allocate space for the parsed descriptors
+
+   IN:
+       pool.............the descriptor_pool
+
+   NOTE:
+       This function must be called after all descriptors have been added
+          with descriptor_pool_add.
+
+*******************************************************************************/
+
+void 
+descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool)
+{
+       u4 size;
+       
+       assert(pool);
+
+       /* TWISTI: paramcount + 1: we don't know if the method is static or   */
+       /* not, i have no better solution yet.                                */
+
+       size =
+               pool->fieldcount * sizeof(typedesc) +
+               pool->methodcount * (sizeof(methoddesc) - sizeof(typedesc)) +
+               pool->paramcount * sizeof(typedesc) +
+               pool->methodcount * sizeof(typedesc);      /* possible `this' pointer */
+
+       pool->descriptorsize = size;
+       if (size) {
+               pool->descriptors = MNEW(u1, size);
+               pool->descriptors_next = pool->descriptors;
+       }
+
+       size = pool->fieldcount + pool->methodcount;
+       if (size) {
+               pool->descriptor_kind = (u1*) DumpMemory::allocate(sizeof(u1) * size);
+               pool->descriptor_kind_next = pool->descriptor_kind;
+       }
+}
+
+
+/* descriptor_pool_parse_field_descriptor **************************************
+   Parse the given field descriptor
+
+   IN:
+       pool.............the descriptor_pool
+          desc.............the field descriptor
+
+   RETURN VALUE:
+       a pointer to the parsed field descriptor, or
+          NULL if an exception has been thrown
+
+   NOTE:
+       descriptor_pool_alloc_parsed_descriptors must be called (once)
+       before this function is used.
+
+*******************************************************************************/
+
+typedesc * 
+descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc)
+{
+       u4 key,slot;
+       descriptor_hash_entry *d;
+       typedesc *td;
+
+       assert(pool);
+       assert(pool->descriptors);
+       assert(pool->descriptors_next);
+
+       /* lookup the descriptor in the hashtable */
+
+       key = utf_hashkey(desc->text, desc->blength);
+       slot = key & (pool->descriptorhash.size - 1);
+       d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
+
+       while (d) {
+               if (d->desc == desc) {
+                       /* found */
+                       if (d->parseddesc.fd)
+                               return d->parseddesc.fd;
+                       break;
+               }
+               d = d->hashlink;
+       }
+
+       assert(d);
+       
+       if (desc->text[0] == '(') {
+               exceptions_throw_classformaterror(pool->referer,
+                                                                                 "Method descriptor used in field reference");
+               return NULL;
+       }
+
+       td = (typedesc *) pool->descriptors_next;
+       pool->descriptors_next += sizeof(typedesc);
+       
+       if (!descriptor_to_typedesc(pool, desc->text, UTF_END(desc), NULL, td))
+               return NULL;
+
+       *(pool->descriptor_kind_next++) = 'f';
+
+       d->parseddesc.fd = td;
+
+       return td;
+}
+
+
+/* descriptor_pool_parse_method_descriptor *************************************
+   Parse the given method descriptor
+
+   IN:
+       pool.............the descriptor_pool
+       desc.............the method descriptor
+       mflags...........the method flags
+          thisclass........classref to the class containing the method.
+                                               This is ignored if mflags contains ACC_STATIC.
+                                               The classref is stored for inserting the 'this' argument.
+
+   RETURN VALUE:
+       a pointer to the parsed method descriptor, or
+          NULL if an exception has been thrown
+
+   NOTE: 
+       descriptor_pool_alloc_parsed_descriptors must be called
+       (once) before this function is used.
+
+*******************************************************************************/
+
+methoddesc * 
+descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc,
+                                                                               s4 mflags,constant_classref *thisclass)
+{
+       u4 key, slot;
+       descriptor_hash_entry *d;
+       methoddesc            *md;
+       typedesc              *td;
+       char *utf_ptr;
+       char *end_pos;
+       s2 paramcount = 0;
+       s2 paramslots = 0;
+
+#ifdef DESCRIPTOR_VERBOSE
+       fprintf(stderr,"descriptor_pool_parse_method_descriptor(%p,%d,%p,",
+                       (void*)pool,(int)mflags,(void*)thisclass);
+       utf_fprint_printable_ascii(stderr,desc); fprintf(stderr,")\n");
+#endif
+
+       assert(pool);
+       assert(pool->descriptors);
+       assert(pool->descriptors_next);
+
+       /* check that it is a method descriptor */
+       
+       if (desc->text[0] != '(') {
+               exceptions_throw_classformaterror(pool->referer,
+                                                                                 "Field descriptor used in method reference");
+               return NULL;
+       }
+
+       /* lookup the descriptor in the hashtable */
+
+       key = utf_hashkey(desc->text, desc->blength);
+       slot = key & (pool->descriptorhash.size - 1);
+       d = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
+
+       /* find an un-parsed descriptor */
+
+       while (d) {
+               if (d->desc == desc)
+                       if (!d->parseddesc.md)
+                               break;
+               d = d->hashlink;
+       }
+
+       assert(d);
+
+       md = (methoddesc *) pool->descriptors_next;
+       pool->descriptors_next += sizeof(methoddesc) - sizeof(typedesc);
+
+       utf_ptr = desc->text + 1; /* skip '(' */
+       end_pos = UTF_END(desc);
+
+       td = md->paramtypes;
+
+       /* count the `this' pointer */
+
+       if ((mflags != ACC_UNDEF) && !(mflags & ACC_STATIC)) {
+               td->type = TYPE_ADR;
+               td->primitivetype = TYPE_ADR;
+               td->arraydim = 0;
+               td->classref = thisclass;
+
+               td++;
+               pool->descriptors_next += sizeof(typedesc);
+               paramcount++;
+               paramslots++;
+       }
+
+       while (*utf_ptr != ')') {
+               /* parse a parameter type */
+
+               if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, &utf_ptr, td))
+                       return NULL;
+
+               if (IS_2_WORD_TYPE(td->type))
+                       paramslots++;
+               
+               td++;
+               pool->descriptors_next += sizeof(typedesc);
+               paramcount++;
+               paramslots++;
+       }
+       utf_ptr++; /* skip ')' */
+
+       /* Skip possible `this' pointer in paramtypes array to allow a possible   */
+       /* memory move later in parse.                                            */
+       /* We store the thisclass reference, so we can later correctly fill in    */
+       /* the parameter slot of the 'this' argument.                             */
+
+       if (mflags == ACC_UNDEF) {
+               td->classref = thisclass;
+               td++;
+               pool->descriptors_next += sizeof(typedesc);
+       }
+
+       /* parse return type */
+
+       if (!descriptor_to_typedesc(pool, utf_ptr, end_pos, NULL,
+                                                               &(md->returntype)))
+               return NULL;
+
+       md->paramcount = paramcount;
+       md->paramslots = paramslots;
+
+       /* If mflags != ACC_UNDEF we parse a real loaded method, so do
+          param prealloc.  Otherwise we do this in stack analysis. */
+
+       if (mflags != ACC_UNDEF) {
+               if (md->paramcount > 0) {
+                       /* allocate memory for params */
+
+                       md->params = MNEW(paramdesc, md->paramcount);
+               }
+               else {
+                       md->params = METHODDESC_NOPARAMS;
+               }
+
+               /* fill the paramdesc */
+               /* md_param_alloc has to be called if md->paramcount == 0,
+                  too, so it can make the reservation for the Linkage Area,
+                  Return Register... */
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+               if (!opt_intrp)
+# endif
+                       {
+                               /* As builtin-functions are native functions, we have
+                                  to pre-allocate for the native ABI. */
+
+                               if (mflags & ACC_METHOD_BUILTIN)
+                                       md_param_alloc_native(md);
+                               else
+                                       md_param_alloc(md);
+                       }
+#endif
+       }
+       else {
+               /* params will be allocated later by
+                  descriptor_params_from_paramtypes if necessary */
+
+               md->params = NULL;
+       }
+
+       *(pool->descriptor_kind_next++) = 'm';
+
+       d->parseddesc.md = md;
+
+       return md;
+}
+
+/* descriptor_params_from_paramtypes *******************************************
+   Create the paramdescs for a method descriptor. This function is called
+   when we know whether the method is static or not. This function may only
+   be called once for each methoddesc, and only if md->params == NULL.
+
+   IN:
+       md...............the parsed method descriptor
+                           md->params MUST be NULL.
+          mflags...........the ACC_* access flags of the method. Only the
+                           ACC_STATIC bit is checked.
+                                               The value ACC_UNDEF is NOT allowed.
+
+   RETURN VALUE:
+       true.............the paramdescs were created successfully
+          false............an exception has been thrown
+
+   POSTCONDITION:
+       md->parms != NULL
+
+*******************************************************************************/
+
+bool descriptor_params_from_paramtypes(methoddesc *md, s4 mflags)
+{
+       typedesc *td;
+
+       assert(md);
+       assert(md->params == NULL);
+       assert(mflags != ACC_UNDEF);
+
+       td = md->paramtypes;
+
+       /* check for `this' pointer */
+
+       if (!(mflags & ACC_STATIC)) {
+               constant_classref *thisclass;
+
+               /* fetch class reference from reserved param slot */
+               thisclass = td[md->paramcount].classref;
+               assert(thisclass);
+
+               if (md->paramcount > 0) {
+                       /* shift param types by 1 argument */
+                       MMOVE(td + 1, td, typedesc, md->paramcount);
+               }
+
+               /* fill in first argument `this' */
+
+               td->type = TYPE_ADR;
+               td->primitivetype = TYPE_ADR;
+               td->arraydim = 0;
+               td->classref = thisclass;
+
+               md->paramcount++;
+               md->paramslots++;
+       }
+
+       /* if the method has params, process them */
+
+       if (md->paramcount > 0) {
+               /* allocate memory for params */
+
+               md->params = MNEW(paramdesc, md->paramcount);
+
+       } else {
+               md->params = METHODDESC_NOPARAMS;
+       }
+
+       /* fill the paramdesc */
+       /* md_param_alloc has to be called if md->paramcount == 0, too, so
+          it can make the reservation for the Linkage Area, Return
+          Register.. */
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+       if (!opt_intrp)
+# endif
+               {
+                       /* As builtin-functions are native functions, we have to
+                          pre-allocate for the native ABI. */
+
+                       if (mflags & ACC_METHOD_BUILTIN)
+                               md_param_alloc_native(md);
+                       else
+                               md_param_alloc(md);
+               }
+#endif
+
+       return true;
+}
+
+
+/* descriptor_pool_get_parsed_descriptors **************************************
+   Return a pointer to the block of parsed descriptors
+
+   IN:
+       pool.............the descriptor_pool
+
+   OUT:
+          *size............if size is non-NULL, this is set to the size of the
+                           parsed descriptor block (in u1)
+
+   RETURN VALUE:
+       a pointer to the block of parsed descriptors
+
+   NOTE:
+       descriptor_pool_alloc_parsed_descriptors must be called (once)
+       before this function is used.
+
+*******************************************************************************/
+
+void * 
+descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size)
+{
+       assert(pool);
+       assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
+       
+       if (size)
+               *size = pool->descriptorsize;
+
+       return pool->descriptors;
+}
+
+
+/* descriptor_pool_get_sizes ***************************************************
+   Get the sizes of the class reference table and the parsed descriptors
+
+   IN:
+       pool.............the descriptor_pool
+
+   OUT:
+       *classrefsize....set to size of the class reference table
+          *descsize........set to size of the parsed descriptors
+
+   NOTE:
+       This function may only be called after both
+              descriptor_pool_create_classrefs, and
+                  descriptor_pool_alloc_parsed_descriptors
+          have been called.
+
+*******************************************************************************/
+
+void 
+descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize, u4 *descsize)
+{
+       assert(pool);
+       assert((!pool->fieldcount && !pool->methodcount) || pool->descriptors);
+       assert(pool->classrefs);
+       assert(classrefsize);
+       assert(descsize);
+
+       *classrefsize = pool->classrefhash.entries * sizeof(constant_classref);
+       *descsize = pool->descriptorsize;
+}
+
+
+/****************************************************************************/
+/* DEBUG HELPERS                                                            */
+/****************************************************************************/
+
+#ifndef NDEBUG
+/* descriptor_debug_print_typedesc *********************************************
+   Print the given typedesc to the given stream
+
+   IN:
+          file.............stream to print to
+          d................the parsed descriptor
+
+*******************************************************************************/
+
+void 
+descriptor_debug_print_typedesc(FILE *file,typedesc *d)
+{
+       int ch;
+
+       if (!d) {
+               fprintf(file,"(typedesc *)NULL");
+               return;
+       }
+       
+       if (d->type == TYPE_ADR) {
+               if (d->classref)
+                       utf_fprint_printable_ascii(file,d->classref->name);
+               else
+                       fprintf(file,"<class=NULL>");
+       }
+       else {
+               switch (d->primitivetype) {
+                       case PRIMITIVETYPE_INT    : ch='I'; break;
+                       case PRIMITIVETYPE_CHAR   : ch='C'; break;
+                       case PRIMITIVETYPE_BYTE   : ch='B'; break;
+                       case PRIMITIVETYPE_SHORT  : ch='S'; break;
+                       case PRIMITIVETYPE_BOOLEAN: ch='Z'; break;
+                       case PRIMITIVETYPE_LONG   : ch='J'; break;
+                       case PRIMITIVETYPE_FLOAT  : ch='F'; break;
+                       case PRIMITIVETYPE_DOUBLE : ch='D'; break;
+                       case PRIMITIVETYPE_VOID   : ch='V'; break;
+                       default                   : ch='!';
+               }
+               fputc(ch,file);
+       }
+       if (d->arraydim)
+               fprintf(file,"[%d]",d->arraydim);
+}
+
+/* descriptor_debug_print_paramdesc ********************************************
+   Print the given paramdesc to the given stream
+
+   IN:
+          file.............stream to print to
+          d................the parameter descriptor
+
+*******************************************************************************/
+
+void
+descriptor_debug_print_paramdesc(FILE *file,paramdesc *d)
+{
+       if (!d) {
+               fprintf(file,"(paramdesc *)NULL");
+               return;
+       }
+       
+       if (d->inmemory) {
+               fprintf(file,"<m%d>",d->regoff);
+       }
+       else {
+               fprintf(file,"<r%d>",d->regoff);
+       }
+}
+
+/* descriptor_debug_print_methoddesc *******************************************
+   Print the given methoddesc to the given stream
+
+   IN:
+          file.............stream to print to
+          d................the parsed descriptor
+
+*******************************************************************************/
+
+void 
+descriptor_debug_print_methoddesc(FILE *file,methoddesc *d)
+{
+       int i;
+       
+       if (!d) {
+               fprintf(file,"(methoddesc *)NULL");
+               return;
+       }
+       
+       fputc('(',file);
+       for (i=0; i<d->paramcount; ++i) {
+               if (i)
+                       fputc(',',file);
+               descriptor_debug_print_typedesc(file,d->paramtypes + i);
+               if (d->params) {
+                       descriptor_debug_print_paramdesc(file,d->params + i);
+               }
+       }
+       if (d->params == METHODDESC_NOPARAMS)
+               fputs("<NOPARAMS>",file);
+       fputc(')',file);
+       descriptor_debug_print_typedesc(file,&(d->returntype));
+}
+
+/* descriptor_pool_debug_dump **************************************************
+   Print the state of the descriptor_pool to the given stream
+
+   IN:
+       pool.............the descriptor_pool
+          file.............stream to print to
+
+*******************************************************************************/
+
+void 
+descriptor_pool_debug_dump(descriptor_pool *pool,FILE *file)
+{
+       u4 slot;
+       u1 *pos;
+       u1 *kind;
+       u4 size;
+       
+       fprintf(file,"======[descriptor_pool for ");
+       utf_fprint_printable_ascii(file,pool->referer->name);
+       fprintf(file,"]======\n");
+
+       fprintf(file,"fieldcount:     %d\n",pool->fieldcount);
+       fprintf(file,"methodcount:    %d\n",pool->methodcount);
+       fprintf(file,"paramcount:     %d\n",pool->paramcount);
+       fprintf(file,"classrefcount:  %d\n",pool->classrefhash.entries);
+       fprintf(file,"descriptorsize: %d bytes\n",pool->descriptorsize);
+       fprintf(file,"classrefsize:   %d bytes\n",
+                       (int)(pool->classrefhash.entries * sizeof(constant_classref)));
+
+       fprintf(file,"class references:\n");
+       for (slot=0; slot<pool->classrefhash.size; ++slot) {
+               classref_hash_entry *c = (classref_hash_entry *) pool->classrefhash.ptr[slot];
+               while (c) {
+                       fprintf(file,"    %4d: ",c->index);
+                       utf_fprint_printable_ascii(file,c->name);
+                       fprintf(file,"\n");
+                       c = c->hashlink;
+               }
+       }
+
+       fprintf(file,"hashed descriptors:\n");
+       for (slot=0; slot<pool->descriptorhash.size; ++slot) {
+               descriptor_hash_entry *c = (descriptor_hash_entry *) pool->descriptorhash.ptr[slot];
+               while (c) {
+                       fprintf(file,"    %p: ",c->parseddesc.any);
+                       utf_fprint_printable_ascii(file,c->desc);
+                       fprintf(file,"\n");
+                       c = c->hashlink;
+               }
+       }
+
+       fprintf(file,"descriptors:\n");
+       if (pool->descriptors) {
+               pos = pool->descriptors;
+               size = pool->descriptors_next - pool->descriptors;
+               fprintf(file,"    size: %d bytes\n",size);
+               
+               if (pool->descriptor_kind) {
+                       kind = pool->descriptor_kind;
+
+                       while (pos < (pool->descriptors + size)) {
+                               fprintf(file,"    %p: ",pos);
+                               switch (*kind++) {
+                                       case 'f':
+                                               descriptor_debug_print_typedesc(file,(typedesc*)pos);
+                                               pos += sizeof(typedesc);
+                                               break;
+                                       case 'm':
+                                               descriptor_debug_print_methoddesc(file,(methoddesc*)pos);
+                                               pos += ((methoddesc*)pos)->paramcount * sizeof(typedesc);
+                                               pos += sizeof(methoddesc) - sizeof(typedesc);
+                                               break;
+                                       default:
+                                               fprintf(file,"INVALID KIND");
+                               }
+                               fputc('\n',file);
+                       }
+               }
+               else {
+                       while (size >= sizeof(void*)) {
+                               fprintf(file,"    %p\n",*((void**)pos));
+                               pos += sizeof(void*);
+                               size -= sizeof(void*);
+                       }
+               }
+       }
+
+       fprintf(file,"==========================================================\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/descriptor.h b/src/vm/descriptor.h
deleted file mode 100644 (file)
index a93f3f9..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/* src/vm/descriptor.h - checking and parsing of field / method descriptors
-
-   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 _DESCRIPTOR_H
-#define _DESCRIPTOR_H
-
-/* forward typedefs ***********************************************************/
-
-typedef struct descriptor_pool descriptor_pool;
-typedef struct typedesc        typedesc;
-typedef struct paramdesc       paramdesc;
-typedef struct methoddesc      methoddesc;
-
-
-#include "config.h"
-
-#include <stdint.h>
-
-#include "vm/types.h"
-
-#include "toolbox/hashtable.h"
-
-#include "vm/class.hpp"
-#include "vm/global.h"
-#include "vm/method.h"
-#include "vm/references.h"
-#include "vm/utf8.h"
-
-#include "arch.h"              /* needed for HAS_ADDRESS_REGISTER_FILE */
-
-
-/* data structures ************************************************************/
-
-/*----------------------------------------------------------------------------*/
-/* Descriptor Pools                                                           */
-/*                                                                            */
-/* A descriptor_pool is a temporary data structure used during loading of     */
-/* a class. The descriptor_pool is used to allocate the table of              */
-/* constant_classrefs the class uses, and for parsing the field and method    */
-/* descriptors which occurr within the class. The inner workings of           */
-/* descriptor_pool are not important for outside code.                        */
-/*                                                                            */
-/* You use a descriptor_pool as follows:                                      */
-/*                                                                            */
-/* 1. create one with descriptor_pool_new                                     */
-/* 2. add all explicit class references with descriptor_pool_add_class        */
-/* 3. add all field/method descriptors with descriptor_pool_add               */
-/* 4. call descriptor_pool_create_classrefs                                   */
-/*    You can now lookup classrefs with descriptor_pool_lookup_classref       */
-/* 5. call descriptor_pool_alloc_parsed_descriptors                           */
-/* 6. for each field descriptor call descriptor_pool_parse_field_descriptor   */
-/*    for each method descriptor call descriptor_pool_parse_method_descriptor */
-/* 7. call descriptor_pool_get_parsed_descriptors                             */
-/*                                                                            */
-/* IMPORTANT: The descriptor_pool functions use DNEW and DMNEW for allocating */
-/*            memory which can be thrown away when the steps above have been  */
-/*            done.                                                           */
-/*----------------------------------------------------------------------------*/
-
-struct descriptor_pool {
-       classinfo         *referer;
-       u4                 fieldcount;
-       u4                 methodcount;
-       u4                 paramcount;
-       u4                 descriptorsize;
-       u1                *descriptors;
-       u1                *descriptors_next;
-       hashtable          descriptorhash;
-       constant_classref *classrefs;
-       hashtable          classrefhash;
-       u1                *descriptor_kind;       /* useful for debugging */
-       u1                *descriptor_kind_next;  /* useful for debugging */
-};
-
-
-/* data structures for parsed field/method descriptors ************************/
-
-struct typedesc {
-       constant_classref *classref;      /* class reference for TYPE_ADR types   */
-       u1                 type;          /* TYPE_??? constant [1]                */
-       u1                 primitivetype; /* (PRIMITIVE)TYPE_??? constant [2]     */
-       u1                 arraydim;      /* array dimension (0 if no array)      */
-};
-
-/* [1]...the type field contains the basic type used within the VM. So ints,  */
-/*       shorts, chars, bytes, booleans all have TYPE_INT.                    */
-/* [2]...the primitivetype field contains the declared type.                  */
-/*       So short is PRIMITIVETYPE_SHORT, char is PRIMITIVETYPE_CHAR.         */
-/*       For non-primitive types primitivetype is TYPE_ADR.                   */
-
-struct paramdesc {
-#if defined(__MIPS__)
-       u1   type;                  /* TYPE_??? of the register allocated         */
-#endif
-       bool     inmemory;          /* argument in register or on stack           */
-       uint32_t index;             /* index into argument register array         */
-       uint32_t regoff;            /* register index or stack offset             */
-};
-
-struct methoddesc {
-       s2         paramcount;      /* number of parameters                       */
-       s2         paramslots;      /* like above but LONG,DOUBLE count twice     */
-       s4         argintreguse;    /* number of used integer argument registers  */
-       s4         argfltreguse;    /* number of used float argument registers    */
-#if defined(HAS_ADDRESS_REGISTER_FILE)
-       s4         argadrreguse;    /* number of used address registers */
-#endif
-       s4         memuse;          /* number of stack slots used                 */
-       paramdesc *params;          /* allocated parameter descriptions [3]       */
-       typedesc   returntype;      /* parsed descriptor of the return type       */
-       typedesc   paramtypes[1];   /* parameter types, variable length!          */
-};
-
-/* [3]...If params is NULL, the parameter descriptions have not yet been      */
-/*       allocated. In this case ___the possible 'this' pointer of the method */
-/*       is NOT counted in paramcount/paramslots and it is NOT included in    */
-/*       the paramtypes array___.                                             */
-/*       If params != NULL, the parameter descriptions have been              */
-/*       allocated, and the 'this' pointer of the method, if any, IS included.*/
-/*       In case the method has no parameters at all, the special value       */
-/*       METHODDESC_NO_PARAMS is used (see below).                            */
-
-/* METHODDESC_NO_PARAMS is a special value for the methoddesc.params field    */
-/* indicating that the method is a static method without any parameters.      */
-/* This special value must be != NULL and it may only be set if               */
-/* md->paramcount == 0.                                                       */
-
-#define METHODDESC_NOPARAMS  ((paramdesc*)1)
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-descriptor_pool * descriptor_pool_new(classinfo *referer);
-
-bool descriptor_pool_add_class(descriptor_pool *pool,utf *name);
-bool descriptor_pool_add(descriptor_pool *pool,utf *desc,int *paramslots);
-
-int  descriptor_to_basic_type(utf *desc);
-int  descriptor_typesize(typedesc *td);
-
-constant_classref * descriptor_pool_create_classrefs(descriptor_pool *pool,
-                                                                                                        s4 *count);
-constant_classref * descriptor_pool_lookup_classref(descriptor_pool *pool,utf *classname);
-
-void descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool);
-
-typedesc *descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc);
-methoddesc *descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc, s4 mflags,
-                                                                                                       constant_classref *thisclass);
-
-bool descriptor_params_from_paramtypes(methoddesc *md, s4 mflags);
-
-void *descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size);
-void descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize,
-                                                          u4 *descsize);
-
-#ifndef NDEBUG
-void descriptor_debug_print_typedesc(FILE *file,typedesc *d);
-void descriptor_debug_print_methoddesc(FILE *file,methoddesc *d);
-void descriptor_debug_print_paramdesc(FILE *file,paramdesc *d);
-void descriptor_pool_debug_dump(descriptor_pool *pool, FILE *file);
-#endif /* !defined(NDEBUG) */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _DESCRIPTOR_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/descriptor.hpp b/src/vm/descriptor.hpp
new file mode 100644 (file)
index 0000000..bf6c69e
--- /dev/null
@@ -0,0 +1,208 @@
+/* src/vm/descriptor.h - checking and parsing of field / method descriptors
+
+   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 _DESCRIPTOR_H
+#define _DESCRIPTOR_H
+
+/* forward typedefs ***********************************************************/
+
+typedef struct descriptor_pool descriptor_pool;
+typedef struct typedesc        typedesc;
+typedef struct paramdesc       paramdesc;
+typedef struct methoddesc      methoddesc;
+
+
+#include "config.h"
+
+#include <stdint.h>
+
+#include "vm/types.h"
+
+#include "toolbox/hashtable.h"
+
+#include "vm/class.hpp"
+#include "vm/global.h"
+#include "vm/method.hpp"
+#include "vm/references.h"
+#include "vm/utf8.h"
+
+#include "arch.h"              /* needed for HAS_ADDRESS_REGISTER_FILE */
+
+
+/* data structures ************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/* Descriptor Pools                                                           */
+/*                                                                            */
+/* A descriptor_pool is a temporary data structure used during loading of     */
+/* a class. The descriptor_pool is used to allocate the table of              */
+/* constant_classrefs the class uses, and for parsing the field and method    */
+/* descriptors which occurr within the class. The inner workings of           */
+/* descriptor_pool are not important for outside code.                        */
+/*                                                                            */
+/* You use a descriptor_pool as follows:                                      */
+/*                                                                            */
+/* 1. create one with descriptor_pool_new                                     */
+/* 2. add all explicit class references with descriptor_pool_add_class        */
+/* 3. add all field/method descriptors with descriptor_pool_add               */
+/* 4. call descriptor_pool_create_classrefs                                   */
+/*    You can now lookup classrefs with descriptor_pool_lookup_classref       */
+/* 5. call descriptor_pool_alloc_parsed_descriptors                           */
+/* 6. for each field descriptor call descriptor_pool_parse_field_descriptor   */
+/*    for each method descriptor call descriptor_pool_parse_method_descriptor */
+/* 7. call descriptor_pool_get_parsed_descriptors                             */
+/*                                                                            */
+/* IMPORTANT: The descriptor_pool functions use DNEW and DMNEW for allocating */
+/*            memory which can be thrown away when the steps above have been  */
+/*            done.                                                           */
+/*----------------------------------------------------------------------------*/
+
+struct descriptor_pool {
+       classinfo         *referer;
+       u4                 fieldcount;
+       u4                 methodcount;
+       u4                 paramcount;
+       u4                 descriptorsize;
+       u1                *descriptors;
+       u1                *descriptors_next;
+       hashtable          descriptorhash;
+       constant_classref *classrefs;
+       hashtable          classrefhash;
+       u1                *descriptor_kind;       /* useful for debugging */
+       u1                *descriptor_kind_next;  /* useful for debugging */
+};
+
+
+/* data structures for parsed field/method descriptors ************************/
+
+struct typedesc {
+       constant_classref *classref;      /* class reference for TYPE_ADR types   */
+       u1                 type;          /* TYPE_??? constant [1]                */
+       u1                 primitivetype; /* (PRIMITIVE)TYPE_??? constant [2]     */
+       u1                 arraydim;      /* array dimension (0 if no array)      */
+};
+
+/* [1]...the type field contains the basic type used within the VM. So ints,  */
+/*       shorts, chars, bytes, booleans all have TYPE_INT.                    */
+/* [2]...the primitivetype field contains the declared type.                  */
+/*       So short is PRIMITIVETYPE_SHORT, char is PRIMITIVETYPE_CHAR.         */
+/*       For non-primitive types primitivetype is TYPE_ADR.                   */
+
+struct paramdesc {
+#if defined(__MIPS__)
+       u1   type;                  /* TYPE_??? of the register allocated         */
+#endif
+       bool     inmemory;          /* argument in register or on stack           */
+       uint32_t index;             /* index into argument register array         */
+       uint32_t regoff;            /* register index or stack offset             */
+};
+
+struct methoddesc {
+       s2         paramcount;      /* number of parameters                       */
+       s2         paramslots;      /* like above but LONG,DOUBLE count twice     */
+       s4         argintreguse;    /* number of used integer argument registers  */
+       s4         argfltreguse;    /* number of used float argument registers    */
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       s4         argadrreguse;    /* number of used address registers */
+#endif
+       s4         memuse;          /* number of stack slots used                 */
+       paramdesc *params;          /* allocated parameter descriptions [3]       */
+       typedesc   returntype;      /* parsed descriptor of the return type       */
+       typedesc   paramtypes[1];   /* parameter types, variable length!          */
+};
+
+/* [3]...If params is NULL, the parameter descriptions have not yet been      */
+/*       allocated. In this case ___the possible 'this' pointer of the method */
+/*       is NOT counted in paramcount/paramslots and it is NOT included in    */
+/*       the paramtypes array___.                                             */
+/*       If params != NULL, the parameter descriptions have been              */
+/*       allocated, and the 'this' pointer of the method, if any, IS included.*/
+/*       In case the method has no parameters at all, the special value       */
+/*       METHODDESC_NO_PARAMS is used (see below).                            */
+
+/* METHODDESC_NO_PARAMS is a special value for the methoddesc.params field    */
+/* indicating that the method is a static method without any parameters.      */
+/* This special value must be != NULL and it may only be set if               */
+/* md->paramcount == 0.                                                       */
+
+#define METHODDESC_NOPARAMS  ((paramdesc*)1)
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+descriptor_pool * descriptor_pool_new(classinfo *referer);
+
+bool descriptor_pool_add_class(descriptor_pool *pool,utf *name);
+bool descriptor_pool_add(descriptor_pool *pool,utf *desc,int *paramslots);
+
+int  descriptor_to_basic_type(utf *desc);
+int  descriptor_typesize(typedesc *td);
+
+constant_classref * descriptor_pool_create_classrefs(descriptor_pool *pool,
+                                                                                                        s4 *count);
+constant_classref * descriptor_pool_lookup_classref(descriptor_pool *pool,utf *classname);
+
+void descriptor_pool_alloc_parsed_descriptors(descriptor_pool *pool);
+
+typedesc *descriptor_pool_parse_field_descriptor(descriptor_pool *pool, utf *desc);
+methoddesc *descriptor_pool_parse_method_descriptor(descriptor_pool *pool, utf *desc, s4 mflags,
+                                                                                                       constant_classref *thisclass);
+
+bool descriptor_params_from_paramtypes(methoddesc *md, s4 mflags);
+
+void *descriptor_pool_get_parsed_descriptors(descriptor_pool *pool, s4 *size);
+void descriptor_pool_get_sizes(descriptor_pool *pool, u4 *classrefsize,
+                                                          u4 *descsize);
+
+#ifndef NDEBUG
+void descriptor_debug_print_typedesc(FILE *file,typedesc *d);
+void descriptor_debug_print_methoddesc(FILE *file,methoddesc *d);
+void descriptor_debug_print_paramdesc(FILE *file,paramdesc *d);
+void descriptor_pool_debug_dump(descriptor_pool *pool, FILE *file);
+#endif /* !defined(NDEBUG) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DESCRIPTOR_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 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 987217cffd4aeea8a3cecba34a73b97f76a19cc5..c2ffe827b7271a49d2ccceb257062840dece4c9c 100644 (file)
@@ -39,7 +39,7 @@
 #include "vm/array.hpp"
 #include "vm/jit/builtin.hpp"
 #include "vm/class.hpp"
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/field.hpp"
 #include "vm/global.h"
index a25d09e3b8b54b91c3513696a437468ea17d53d5..2bb538290cebab76d0b88c88f1dea68778c6affb 100644 (file)
@@ -34,7 +34,7 @@ typedef struct fieldinfo fieldinfo;
 #include "config.h"
 #include "vm/types.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/class.hpp"
 #include "vm/global.h"
 #include "vm/loader.hpp"
diff --git a/src/vm/finalizer.c b/src/vm/finalizer.c
deleted file mode 100644 (file)
index ea331ec..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/* src/vm/finalizer.c - finalizer linked list and thread
-
-   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 <stdlib.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "threads/condition.hpp"
-#include "threads/mutex.hpp"
-#include "threads/thread.hpp"
-
-#include "vm/jit/builtin.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/global.h"
-#include "vm/options.h"
-#include "vm/vm.hpp"
-
-#include "vm/jit/asmpart.h"
-
-
-/* global variables ***********************************************************/
-
-#if defined(ENABLE_THREADS)
-static Mutex     *finalizer_thread_mutex;
-static Condition *finalizer_thread_cond;
-#endif
-
-
-/* finalizer_init **************************************************************
-
-   Initializes the finalizer global lock and the linked list.
-
-*******************************************************************************/
-
-bool finalizer_init(void)
-{
-       TRACESUBSYSTEMINITIALIZATION("finalizer_init");
-
-#if defined(ENABLE_THREADS)
-       finalizer_thread_mutex = Mutex_new();
-       finalizer_thread_cond  = Condition_new();
-#endif
-
-       /* everything's ok */
-
-       return true;
-}
-
-
-/* finalizer_thread ************************************************************
-
-   This thread waits on an object for a notification and the runs the
-   finalizers (finalizer thread).  This is necessary because of a
-   possible deadlock in the GC.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS)
-static void finalizer_thread(void)
-{
-       while (true) {
-               /* get the lock on the finalizer mutex, so we can call wait */
-
-               Mutex_lock(finalizer_thread_mutex);
-
-               /* wait forever on that condition till we are signaled */
-       
-               Condition_wait(finalizer_thread_cond, finalizer_thread_mutex);
-
-               /* leave the lock */
-
-               Mutex_unlock(finalizer_thread_mutex);
-
-#if !defined(NDEBUG)
-               if (opt_DebugFinalizer)
-                       log_println("[finalizer thread    : status=awake]");
-#endif
-
-               /* and call the finalizers */
-
-               gc_invoke_finalizers();
-
-#if !defined(NDEBUG)
-               if (opt_DebugFinalizer)
-                       log_println("[finalizer thread    : status=sleeping]");
-#endif
-       }
-}
-#endif
-
-
-/* finalizer_start_thread ******************************************************
-
-   Starts the finalizer thread.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS)
-bool finalizer_start_thread(void)
-{
-       utf *name;
-
-       name = utf_new_char("Finalizer");
-
-       if (!threads_thread_start_internal(name, finalizer_thread))
-               return false;
-
-       /* everything's ok */
-
-       return true;
-}
-#endif
-
-
-/* finalizer_notify ************************************************************
-
-   Notifies the finalizer thread that it should run the
-   gc_invoke_finalizers from the GC.
-
-*******************************************************************************/
-
-void finalizer_notify(void)
-{
-#if !defined(NDEBUG)
-       if (opt_DebugFinalizer)
-               log_println("[finalizer notified]");
-#endif
-
-#if defined(ENABLE_THREADS)
-       /* get the lock on the finalizer lock object, so we can call wait */
-
-       Mutex_lock(finalizer_thread_mutex);
-
-       /* signal the finalizer thread */
-
-       Condition_signal(finalizer_thread_cond);
-
-       /* leave the lock */
-
-       Mutex_unlock(finalizer_thread_mutex);
-#else
-       /* if we don't have threads, just run the finalizers */
-
-       gc_invoke_finalizers();
-#endif
-}
-
-
-/* finalizer_run ***************************************************************
-
-   Actually run the finalizer functions.
-
-*******************************************************************************/
-
-void finalizer_run(void *o, void *p)
-{
-       java_handle_t *h;
-       classinfo     *c;
-
-       h = (java_handle_t *) o;
-
-#if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
-       /* XXX this is only a dirty hack to make Boehm work with handles */
-
-       h = LLNI_WRAP((java_object_t *) h);
-#endif
-
-       LLNI_class_get(h, c);
-
-#if !defined(NDEBUG)
-       if (opt_DebugFinalizer) {
-               log_start();
-               log_print("[finalizer running   : o=%p p=%p class=", o, p);
-               class_print(c);
-               log_print("]");
-               log_finish();
-       }
-#endif
-
-       /* call the finalizer function */
-
-       (void) vm_call_method(c->finalizer, h);
-
-#if !defined(NDEBUG)
-       if (opt_DebugFinalizer && (exceptions_get_exception() != NULL)) {
-               log_println("[finalizer exception]");
-               exceptions_print_stacktrace();
-       }
-#endif
-
-       /* if we had an exception in the finalizer, ignore it */
-
-       exceptions_clear_exception();
-}
-
-
-/*
- * 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/finalizer.cpp b/src/vm/finalizer.cpp
new file mode 100644 (file)
index 0000000..690a09a
--- /dev/null
@@ -0,0 +1,240 @@
+/* src/vm/finalizer.c - finalizer linked list and thread
+
+   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 <stdlib.h>
+
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "threads/condition.hpp"
+#include "threads/mutex.hpp"
+#include "threads/thread.hpp"
+
+#include "vm/jit/builtin.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/options.h"
+#include "vm/vm.hpp"
+
+#include "vm/jit/asmpart.h"
+
+
+/* global variables ***********************************************************/
+
+#if defined(ENABLE_THREADS)
+static Mutex     *finalizer_thread_mutex;
+static Condition *finalizer_thread_cond;
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* finalizer_init **************************************************************
+
+   Initializes the finalizer global lock and the linked list.
+
+*******************************************************************************/
+
+bool finalizer_init(void)
+{
+       TRACESUBSYSTEMINITIALIZATION("finalizer_init");
+
+#if defined(ENABLE_THREADS)
+       finalizer_thread_mutex = new Mutex();
+       finalizer_thread_cond  = new Condition();
+#endif
+
+       /* everything's ok */
+
+       return true;
+}
+
+
+/* finalizer_thread ************************************************************
+
+   This thread waits on an object for a notification and the runs the
+   finalizers (finalizer thread).  This is necessary because of a
+   possible deadlock in the GC.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+static void finalizer_thread(void)
+{
+       while (true) {
+               /* get the lock on the finalizer mutex, so we can call wait */
+
+               finalizer_thread_mutex->lock();
+
+               /* wait forever on that condition till we are signaled */
+       
+               finalizer_thread_cond->wait(finalizer_thread_mutex);
+
+               /* leave the lock */
+
+               finalizer_thread_mutex->unlock();
+
+#if !defined(NDEBUG)
+               if (opt_DebugFinalizer)
+                       log_println("[finalizer thread    : status=awake]");
+#endif
+
+               /* and call the finalizers */
+
+               gc_invoke_finalizers();
+
+#if !defined(NDEBUG)
+               if (opt_DebugFinalizer)
+                       log_println("[finalizer thread    : status=sleeping]");
+#endif
+       }
+}
+#endif
+
+
+/* finalizer_start_thread ******************************************************
+
+   Starts the finalizer thread.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+bool finalizer_start_thread(void)
+{
+       utf *name;
+
+       name = utf_new_char("Finalizer");
+
+       if (!threads_thread_start_internal(name, finalizer_thread))
+               return false;
+
+       /* everything's ok */
+
+       return true;
+}
+#endif
+
+
+/* finalizer_notify ************************************************************
+
+   Notifies the finalizer thread that it should run the
+   gc_invoke_finalizers from the GC.
+
+*******************************************************************************/
+
+void finalizer_notify(void)
+{
+#if !defined(NDEBUG)
+       if (opt_DebugFinalizer)
+               log_println("[finalizer notified]");
+#endif
+
+#if defined(ENABLE_THREADS)
+       /* get the lock on the finalizer lock object, so we can call wait */
+
+       finalizer_thread_mutex->lock();
+
+       /* signal the finalizer thread */
+
+       finalizer_thread_cond->signal();
+
+       /* leave the lock */
+
+       finalizer_thread_mutex->unlock();
+#else
+       /* if we don't have threads, just run the finalizers */
+
+       gc_invoke_finalizers();
+#endif
+}
+
+
+/* finalizer_run ***************************************************************
+
+   Actually run the finalizer functions.
+
+*******************************************************************************/
+
+void finalizer_run(void *o, void *p)
+{
+       java_handle_t *h;
+       classinfo     *c;
+
+       h = (java_handle_t *) o;
+
+#if !defined(ENABLE_GC_CACAO) && defined(ENABLE_HANDLES)
+       /* XXX this is only a dirty hack to make Boehm work with handles */
+
+       h = LLNI_WRAP((java_object_t *) h);
+#endif
+
+       LLNI_class_get(h, c);
+
+#if !defined(NDEBUG)
+       if (opt_DebugFinalizer) {
+               log_start();
+               log_print("[finalizer running   : o=%p p=%p class=", o, p);
+               class_print(c);
+               log_print("]");
+               log_finish();
+       }
+#endif
+
+       /* call the finalizer function */
+
+       (void) vm_call_method(c->finalizer, h);
+
+#if !defined(NDEBUG)
+       if (opt_DebugFinalizer && (exceptions_get_exception() != NULL)) {
+               log_println("[finalizer exception]");
+               exceptions_print_stacktrace();
+       }
+#endif
+
+       /* if we had an exception in the finalizer, ignore it */
+
+       exceptions_clear_exception();
+}
+
+#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:
+ */
diff --git a/src/vm/finalizer.h b/src/vm/finalizer.h
deleted file mode 100644 (file)
index 04abf9e..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* src/vm/finalizer.h - finalizer linked list and thread header
-
-   Copyright (C) 1996-2005, 2006, 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 _FINALIZER_H
-#define _FINALIZER_H
-
-#include "config.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "vm/types.h"
-
-#include "vm/global.h"
-
-
-/* function prototypes ********************************************************/
-
-bool finalizer_init(void);
-bool finalizer_start_thread(void);
-void finalizer_notify(void);
-void finalizer_run(void *o, void *p);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _FINALIZER_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/finalizer.hpp b/src/vm/finalizer.hpp
new file mode 100644 (file)
index 0000000..04abf9e
--- /dev/null
@@ -0,0 +1,65 @@
+/* src/vm/finalizer.h - finalizer linked list and thread header
+
+   Copyright (C) 1996-2005, 2006, 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 _FINALIZER_H
+#define _FINALIZER_H
+
+#include "config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "vm/types.h"
+
+#include "vm/global.h"
+
+
+/* function prototypes ********************************************************/
+
+bool finalizer_init(void);
+bool finalizer_start_thread(void);
+void finalizer_notify(void);
+void finalizer_run(void *o, void *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FINALIZER_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:
+ */
index 6858eb6e006ad430e980071ace9abacbfd7b247f..b8a0d601326b5b830b68e14a474d44ca009341df 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "native/vm/reflection.hpp"
 
-#include "vm/access.h"
+#include "vm/access.hpp"
 #include "vm/jit/builtin.hpp"
 #include "vm/global.h"
 #include "vm/globals.hpp"
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 ce48bfff76f1f82a75b9aca5e1209cc6f3469d3c..7da89972163e791d47096097842bd88912f20016 100644 (file)
@@ -173,8 +173,8 @@ libjit_la_SOURCES = \
        linenumbertable.hpp \
        methodtree.c \
        methodtree.h \
-       parse.c \
-       parse.h \
+       parse.cpp \
+       parse.hpp \
        patcher-common.cpp \
        patcher-common.hpp \
        $(RECOMPILE_SOURCES) \
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 9ca4373a65fda07b4c20debf2ed17e45cfdce5db..619a039515bb6c507ed554af03d02d022f9af0e1 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "vm/jit/codegen-common.hpp"
 #include "vm/jit/jit.hpp"
-#include "vm/jit/inline/inline.h"
+#include "vm/jit/inline/inline.hpp"
 
 
 /* function prototypes ********************************************************/
index 6dab39a3c128dbdfbec147101fa9faf808534992..bb5f050f82ced2be5400d5c93ba7bafe8b08e500 100644 (file)
@@ -57,7 +57,7 @@
 #include "vm/jit/emit-common.hpp"
 #include "vm/jit/jit.hpp"
 #include "vm/jit/linenumbertable.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/patcher-common.hpp"
 #include "vm/jit/reg.h"
 #include "vm/jit/replace.hpp"
index 496834761c646923fdd60750d8c98553d8ae80fd..c968be9862d9c4615c40fa7a83ec2682e56f0970 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "vm/jit/alpha/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 
 #include "vm/jit/abi.h"
index a340cf5663552d1a4644ebe8b9cdd120645c8a29..6b1d37d3de3e779ce33b90401ca989235d49ceb0 100644 (file)
@@ -35,9 +35,9 @@
 #include "native/llni.h"
 
 #include "vm/array.hpp"
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #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 09f3d0b5f2cb5c0d260d06faa7a807b5963748db..4b86e510f050e22bf584c9850842b51fb17c4a26 100644 (file)
@@ -57,7 +57,7 @@
 #include "vm/jit/jit.hpp"
 #include "vm/jit/linenumbertable.hpp"
 #include "vm/jit/methodheader.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/patcher-common.hpp"
 #include "vm/jit/reg.h"
 
index bdf6a14f918d2debb0234f7a15315cfef23a0531..c0f00f81a395d33a453e14195e0c2eb20ab3b053 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "vm/jit/arm/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 
 #include "vm/jit/abi.h"
index 39448913e38f885b47bcac9de6aea6312fc837ce..62fa58212ce04c02417e945ad0ca2d2fffd88e04 100644 (file)
@@ -67,7 +67,7 @@
 #include "vm/global.h"
 #include "vm/globals.hpp"
 #include "vm/initialize.hpp"
-#include "vm/linker.h"
+#include "vm/linker.hpp"
 #include "vm/loader.hpp"
 #include "vm/options.h"
 #include "vm/primitive.hpp"
index 2a03455299c52069529db48f81d0e9b410789cb4..df4f73af20b5315861ce0b736bf46f7acd347858 100644 (file)
@@ -38,7 +38,7 @@ typedef struct builtintable_entry builtintable_entry;
 
 #include "toolbox/logging.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/utf8.h"
 
 
index cd082dd19f93b2963be4985037c6e11e7f771da1..0cbf0a2a8001463eb5e9dd3756b8d9bca0862862 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"
 #include "vm/jit/linenumbertable.hpp"
index 173c272c5b5d6eac1b21355ca05501e61a31d3fc..dd1768e588f642b96a4e26bfeaf306bb0f45de03 100644 (file)
@@ -65,7 +65,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..b988853b39629bf11a957320305f2b67b14ffc86 100644 (file)
@@ -41,9 +41,9 @@ typedef struct dataref                dataref;
 #include "toolbox/list.hpp"
 
 #include "vm/jit/builtin.hpp"
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/references.h"
 
 #include "vm/jit/dseg.h"
index 04bdcbba884ea06d04138b0031fffee4e8650b7c..370a64bd024fd6463f35a6bb03e6077bcc67d076 100644 (file)
@@ -656,14 +656,48 @@ void emit_label_br(codegendata *cd, s4 label)
 
 #if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER
 
-void emit_label_beqz(codegendata *cd, s4 label, s4 reg)
+void emit_label_beqz(codegendata* cd, int label, int reg)
 {
        emit_label_bccz(cd, label, BRANCH_EQ, reg, BRANCH_OPT_NONE);
 }
 
+void emit_label_bnez(codegendata* cd, int label, int reg)
+{
+       emit_label_bccz(cd, label, BRANCH_NE, reg, BRANCH_OPT_NONE);
+}
+
+void emit_label_bltz(codegendata* cd, int label, int reg)
+{
+       emit_label_bccz(cd, label, BRANCH_LT, reg, BRANCH_OPT_NONE);
+}
+
+void emit_label_bgtz(codegendata* cd, int label, int reg)
+{
+       emit_label_bccz(cd, label, BRANCH_GT, reg, BRANCH_OPT_NONE);
+}
+
 #endif /* SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER */
 
 
+/* emit_label_bxx **************************************************************
+
+   Wrappers for label-branches on two integer registers.
+
+   We use PACK_REGS here, so we don't have to change the branchref
+   data structure and the emit_bccz function.
+
+*******************************************************************************/
+
+#if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS
+
+void emit_label_bne(codegendata* cd, int label, int s1, int s2)
+{
+       emit_label_bccz(cd, label, BRANCH_NE, PACK_REGS(s1, s2), BRANCH_OPT_NONE);
+}
+
+#endif /* SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS */
+
+
 /* emit_label_bxx **************************************************************
 
    Wrappers for label-branches on condition codes.
index 880f633cd648caffac9e3be970f8e3947da0a451..e499f557e3e581e282d241e6e201163964dcb04a 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vm/jit/emit-common.hpp - common code emitter functions
 
-   Copyright (C) 2006, 2007 R. Grafl, A. Krall, C. Kruegel, C. Oates,
-   R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
-   C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
-   Institut f. Computersprachen - TU Wien
+   Copyright (C) 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
@@ -159,7 +157,14 @@ void emit_label_bcc(codegendata *cd, s4 label, s4 condition, u4 options);
 void emit_label_br(codegendata *cd, s4 label);
 
 #if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER
-void emit_label_beqz(codegendata *cd, s4 label, s4 reg);
+void emit_label_beqz(codegendata* cd, int label, int reg);
+void emit_label_bnez(codegendata* cd, int label, int reg);
+void emit_label_bltz(codegendata* cd, int label, int reg);
+void emit_label_bgtz(codegendata* cd, int label, int reg);
+#endif
+
+#if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS
+void emit_label_bne(codegendata* cd, int label, int s1, int s2);
 #endif
 
 #if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER
index cfcac31c3dc4e1a5b114b35a39427448dd0e9948..2a7958deac3b2af7435d49cc681d3e32e694d865 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/os.hpp"
 
 #include "vm/jit/abi.h"
index 1252e136ac09e7e1c89e22669df606846d4db23e..b5dbe1b322ef39eef90e1e3e98a73c4069b00c0c 100644 (file)
@@ -59,7 +59,7 @@
 #include "vm/jit/emit-common.hpp"
 #include "vm/jit/jit.hpp"
 #include "vm/jit/linenumbertable.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/patcher-common.hpp"
 #include "vm/jit/reg.h"
 #include "vm/jit/replace.hpp"
index dbaf089b81d80c4ba3f5b02f8ae5e0f0bcda1b70..f304686bc70606edb2980a96ee3be4440365bfe5 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "vm/jit/i386/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 
 #include "vm/jit/abi.h"
index 8b46e133284226aa11fffb07bd6e6b8ac2b1e63f..e3ca1468f4926c13255d4f298680792ec78bf527 100644 (file)
@@ -31,8 +31,8 @@ noinst_LTLIBRARIES = \
        libinline.la
 
 libinline_la_SOURCES = \
-       inline.c \
-       inline.h \
+       inline.cpp \
+       inline.hpp \
        inline_debug.inc
 
 
diff --git a/src/vm/jit/inline/inline.c b/src/vm/jit/inline/inline.c
deleted file mode 100644 (file)
index ca7fb42..0000000
+++ /dev/null
@@ -1,3237 +0,0 @@
-/* src/vm/jit/inline/inline.c - method inlining
-
-   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 <limits.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "threads/lock.hpp"
-#include "threads/mutex.hpp"
-#include "threads/thread.hpp"
-
-#include "toolbox/logging.h"
-
-#include "vm/jit/builtin.hpp"
-#include "vm/class.hpp"
-#include "vm/global.h"
-#include "vm/initialize.hpp"
-#include "vm/method.h"
-#include "vm/options.h"
-#include "vm/statistics.h"
-
-#include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
-#include "vm/jit/reg.h"
-#include "vm/jit/show.hpp"
-#include "vm/jit/stack.h"
-
-#include "vm/jit/inline/inline.h"
-#include "vm/jit/loop/loop.h"
-
-#include "vm/jit/verify/typecheck.h"
-
-
-/* algorithm tuning constants *************************************************/
-
-/* Algorithm Selection                                                        */
-/* Define exactly one of the following three to select the inlining           */
-/* heuristics.                                                                */
-
-/*#define INLINE_DEPTH_FIRST*/
-/*#define INLINE_BREADTH_FIRST*/
-#define INLINE_KNAPSACK
-
-/* Parameters for knapsack heuristics:                                        */
-
-#if defined(INLINE_KNAPSACK)
-
-#define INLINE_COUNTDOWN_INIT       1000
-#define INLINE_COST_OFFSET          -16
-#define INLINE_COST_BUDGET          100
-/*#define INLINE_WEIGHT_BUDGET        5.0*/
-/*#define INLINE_ADD_NEGATIVE_TO_BUDGET*/
-/*#define INLINE_MAX_DEPTH            3*/
-/*#define INLINE_DIVIDE_COST_BY_FREQ */
-
-#endif
-
-/* Parameters for depth-first heuristics:                                     */
-
-#if defined(INLINE_DEPTH_FIRST)
-
-#define INLINE_MAX_DEPTH            3
-#define INLINE_MAX_BLOCK_EXPANSION  10
-/*#define INLINE_MAX_ICMD_EXPANSION  10*/
-/*#define INLINE_CANCEL_ON_THRESHOLD*/
-
-#endif
-
-/* Parameters for breadth-first heuristics:                                   */
-
-#if defined(INLINE_BREADTH_FIRST)
-
-/*#define INLINE_MAX_BLOCK_EXPANSION  10*/
-#define INLINE_MAX_ICMD_EXPANSION  5
-
-#endif
-
-
-/* debugging ******************************************************************/
-
-#if !defined(NDEBUG)
-#define INLINE_VERBOSE
-#define DOLOG(code)       do{ if (opt_TraceInlining >= 2) { code; } }while(0)
-#define DOLOG_SHORT(code) do{ if (opt_TraceInlining >= 1) { code; } }while(0)
-#else
-#define DOLOG(code)
-#endif
-
-#if defined(ENABLE_VERIFIER) && !defined(NDEBUG)
-/* Define this to verify the resulting code after inlining.                 */
-/* Note: This is only useful for development and may require patches to the */
-/*       verifier code.                                                     */
-/* #define INLINE_VERIFY_RESULT */
-#endif
-
-
-/* types **********************************************************************/
-
-typedef struct inline_node inline_node;
-typedef struct inline_target_ref inline_target_ref;
-typedef struct inline_context inline_context;
-typedef struct inline_block_map inline_block_map;
-typedef struct inline_site inline_site;
-typedef struct inline_candidate inline_candidate;
-
-struct inline_node {
-       inline_context *ctx;
-
-       jitdata *jd;
-       methodinfo *m;
-       inline_node *children;
-       inline_node *next;                             /* next node at this depth */
-       inline_node *prev;                             /* prev node at this depth */
-       int depth;                                  /* inlining depth, 0 for root */
-
-       /* info about the call site (if depth > 0)*/
-       inline_node *parent;                /* node of the caller (NULL for root) */
-       basicblock *callerblock;         /* original block containing the INVOKE* */
-       instruction *callerins;               /* the original INVOKE* instruction */
-       s4 callerpc;
-       s4 *n_passthroughvars;
-       int n_passthroughcount;
-       int n_selfpassthroughcount;  /* # of pass-through vars of the call itself */
-       exception_entry **o_handlers;
-       int n_handlercount;                 /* # of handlers protecting this call */
-       int n_resultlocal;
-       int synclocal;                    /* variable used for synchr., or UNUSED */
-       bool isstatic;                                   /* this is a static call */
-
-       bool blockbefore;                  /* block boundary before inlined body? */
-       bool blockafter;                   /* block boundary after inlined body?  */
-
-       /* info about the callee */
-       int localsoffset;
-       int prolog_instructioncount;         /* # of ICMDs in the inlining prolog */
-       int epilog_instructioncount;         /* # of ICMDs in the inlining epilog */
-       int extra_instructioncount;
-       int extra_exceptiontablelength;   /* # of extra handlers to put in caller */
-       bool synchronize;                /* do we have to synchronize enter/exit? */
-       basicblock *handler_monitorexit;     /* handler for synchronized inlinees */
-       s4 *varmap;
-
-       /* cumulative values */
-       int cumul_instructioncount;  /* ICMDs in this node and its children       */
-       int cumul_basicblockcount;   /* BBs started by this node and its children */
-       int cumul_basicblockcount_root;  /* BBs that have to be added to the root */
-                                        /* node if this node is inlined          */
-       int cumul_blockmapcount;
-       int cumul_maxlocals;
-       int cumul_exceptiontablelength;
-
-       /* output */
-       instruction *inlined_iinstr;
-       instruction *inlined_iinstr_cursor;
-       basicblock *inlined_basicblocks;
-       basicblock *inlined_basicblocks_cursor;
-
-       /* register data */
-       registerdata *regdata;
-
-       /* temporary */
-       inline_target_ref *refs;
-       instruction *inline_start_instruction;
-       s4 *javalocals;
-
-       /* XXX debug */
-       char *indent;
-       int debugnr;
-};
-
-struct inline_target_ref {
-       inline_target_ref *next;
-       union {
-               basicblock **block;
-               s4 *nr;
-       } ref;
-       basicblock *target;
-       bool isnumber;
-};
-
-struct inline_block_map {
-       inline_node *iln;
-       basicblock *o_block;
-       basicblock *n_block;
-};
-
-struct inline_context {
-       inline_node *master;
-
-       jitdata *resultjd;
-
-       inline_candidate *candidates;
-
-       int next_block_number;
-       inline_block_map *blockmap;
-       int blockmap_index;
-
-       int maxinoutdepth;
-
-       bool stopped;
-
-       int next_debugnr; /* XXX debug */
-};
-
-struct inline_site {
-       bool              speculative;  /* true, if inlining would be speculative */
-       bool              inlined;      /* true, if this site has been inlined    */
-
-       basicblock       *bptr;         /* basic block containing the call site   */
-       instruction      *iptr;         /* the invocation instruction             */
-       exception_entry **handlers;     /* active handlers at the call site       */
-       s4                nhandlers;    /* number of active handlers              */
-       s4                pc;           /* PC of the invocation instruction       */
-};
-
-struct inline_candidate {
-       inline_candidate *next;
-       int freq;
-       int cost;
-       double weight;
-       inline_node *caller;
-       methodinfo *callee;
-       inline_site site;
-};
-
-
-/* prototypes *****************************************************************/
-
-static bool inline_analyse_code(inline_node *iln);
-static void inline_post_process(jitdata *jd);
-
-
-/* debug helpers **************************************************************/
-
-#if !defined(NDEBUG)
-#include "inline_debug.inc"
-#endif
-
-
-/* statistics *****************************************************************/
-
-/*#define INLINE_STATISTICS*/
-
-#if !defined(NDEBUG)
-#define INLINE_STATISTICS
-#endif
-
-#if defined(INLINE_STATISTICS)
-int inline_stat_roots = 0;
-int inline_stat_roots_transformed = 0;
-int inline_stat_inlined_nodes = 0;
-int inline_stat_max_depth = 0;
-
-void inline_print_stats()
-{
-       printf("inlining statistics:\n");
-       printf("    roots analysed   : %d\n", inline_stat_roots);
-       printf("    roots transformed: %d\n", inline_stat_roots_transformed);
-       printf("    inlined nodes    : %d\n", inline_stat_inlined_nodes);
-       printf("    max depth        : %d\n", inline_stat_max_depth);
-}
-#endif
-
-
-/* compilation of callees *****************************************************/
-
-static bool inline_jit_compile_intern(jitdata *jd)
-{
-       methodinfo *m;
-
-       /* XXX should share code with jit.c */
-
-       assert(jd);
-
-       /* XXX initialize the static function's class */
-
-       m = jd->m;
-
-       /* call the compiler passes ***********************************************/
-
-       /* call parse pass */
-
-       DOLOG( log_message_class("Parsing ", m->clazz) );
-       if (!parse(jd)) {
-               return false;
-       }
-
-       /* call stack analysis pass */
-
-       if (!stack_analyse(jd)) {
-               return false;
-       }
-
-       return true;
-}
-
-
-static bool inline_jit_compile(inline_node *iln)
-{
-       bool                r;
-       methodinfo         *m;
-       jitdata            *jd;
-
-       /* XXX should share code with jit.c */
-
-       assert(iln);
-       m = iln->m;
-       assert(m);
-
-       /* enter a monitor on the method */
-
-       Mutex_lock(m->mutex);
-
-       /* allocate jitdata structure and fill it */
-
-       jd = jit_jitdata_new(m);
-       iln->jd = jd;
-
-       jd->flags = 0; /* XXX */
-
-       /* initialize the register allocator */
-
-       reg_setup(jd);
-
-       /* setup the codegendata memory */
-
-       /* XXX do a pseudo setup */
-       jd->cd = DNEW(codegendata);
-       MZERO(jd->cd, codegendata, 1);
-       jd->cd->method = m;
-       /* XXX uses too much dump memory codegen_setup(jd); */
-
-       /* now call internal compile function */
-
-       r = inline_jit_compile_intern(jd);
-
-       if (r) {
-               iln->regdata = jd->rd;
-       }
-
-       /* free some memory */
-#if 0
-
-#if defined(ENABLE_JIT)
-# if defined(ENABLE_INTRP)
-       if (!opt_intrp)
-# endif
-               codegen_free(jd);
-#endif
-
-#endif
-
-       /* leave the monitor */
-
-       Mutex_unlock(m->mutex);
-
-       return r;
-}
-
-
-/* inlining tree handling *****************************************************/
-
-static void inline_insert_inline_node(inline_node *parent, inline_node *child)
-{
-       inline_node *first;
-       inline_node *succ;
-
-       assert(parent && child);
-
-       child->parent = parent;
-
-       child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
-
-       first = parent->children;
-       if (!first) {
-               /* insert as only node */
-               parent->children = child;
-               child->next = child;
-               child->prev = child;
-               return;
-       }
-
-       /* {there is at least one child already there} */
-
-       /* XXX is this search necessary, or could we always add at the end? */
-
-       succ = first;
-       while (succ->callerpc < child->callerpc) {
-               succ = succ->next;
-               if (succ == first) {
-                       /* insert as last node */
-                       child->prev = first->prev;
-                       child->next = first;
-                       child->prev->next = child;
-                       child->next->prev = child;
-                       return;
-               }
-       }
-
-       assert(succ->callerpc > child->callerpc);
-
-       /* insert before succ */
-
-       child->prev = succ->prev;
-       child->next = succ;
-       child->prev->next = child;
-       child->next->prev = child;
-
-       if (parent->children == succ)
-               parent->children = child;
-}
-
-
-static void inline_remove_inline_node(inline_node *parent, inline_node *child)
-{
-       assert(parent);
-       assert(child);
-       assert(child->parent == parent);
-
-       if (child->prev == child) {
-               /* remove the only child node */
-               parent->children = NULL;
-       }
-       else {
-               child->prev->next = child->next;
-               child->next->prev = child->prev;
-
-               if (parent->children == child)
-                       parent->children = child->next;
-       }
-}
-
-
-/* inlining candidate handling ************************************************/
-
-#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
-static void inline_add_candidate(inline_context *ctx,
-                                                                inline_node *caller,
-                                                                methodinfo *callee,
-                                                                inline_site *site)
-{
-       inline_candidate **link;
-       inline_candidate *cand;
-
-       cand = DNEW(inline_candidate);
-#if defined(INLINE_DIVIDE_COST_BY_FREQ)
-       cand->freq = INLINE_COUNTDOWN_INIT - callee->hitcountdown;
-       if (cand->freq < 1)
-#endif
-               cand->freq = 1;
-#if defined(INLINE_KNAPSACK)
-       cand->cost = callee->jcodelength + INLINE_COST_OFFSET;
-#endif
-#if defined(INLINE_BREADTH_FIRST)
-       cand->cost = caller->depth;
-#endif
-       cand->caller = caller;
-       cand->callee = callee;
-       cand->site = *site;
-
-       cand->weight = (double)cand->cost / cand->freq;
-
-       for (link = &(ctx->candidates); ; link = &((*link)->next)) {
-               if (!*link || (*link)->weight > cand->weight) {
-                       cand->next = *link;
-                       *link = cand;
-                       break;
-               }
-       }
-}
-#endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
-
-#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
-static inline_candidate * inline_pick_best_candidate(inline_context *ctx)
-{
-       inline_candidate *cand;
-
-       cand = ctx->candidates;
-
-       if (cand)
-               ctx->candidates = cand->next;
-
-       return cand;
-}
-#endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
-
-#if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
-static void inline_candidate_println(inline_candidate *cand)
-{
-       printf("%10g (%5d / %5d) depth %2d ",
-                       cand->weight, cand->cost, cand->freq, cand->caller->depth + 1);
-       method_println(cand->callee);
-}
-#endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
-
-
-#if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
-static void inline_candidates_println(inline_context *ctx)
-{
-       inline_candidate *cand;
-
-       for (cand = ctx->candidates; cand != NULL; cand = cand->next) {
-               printf("    ");
-               inline_candidate_println(cand);
-       }
-}
-#endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
-
-
-/* variable handling **********************************************************/
-
-static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
-{
-       s4 index;
-       s4 newcount;
-
-       index = jd->vartop++;
-       if (index >= jd->varcount) {
-               newcount = jd->vartop * 2; /* XXX */
-               jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
-               MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
-               jd->varcount = newcount;
-       }
-
-       jd->var[index].type = type;
-       jd->var[index].flags = flags;
-
-       return index;
-}
-
-
-static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
-{
-       varinfo *v;
-       s4       newidx;
-
-       v = &(origjd->var[origidx]);
-
-       newidx = inline_new_variable(jd, v->type, v->flags);
-
-       jd->var[newidx].vv = v->vv;
-
-       return newidx;
-}
-
-
-static s4 inline_new_temp_variable(jitdata *jd, s4 type)
-{
-       return inline_new_variable(jd, type, 0);
-}
-
-
-static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
-{
-       s4 idx;
-
-       idx = varmap[index];
-
-       if (idx < 0) {
-               idx = inline_new_variable_clone(jd, origjd, index);
-               varmap[index] = idx;
-       }
-
-       return idx;
-}
-
-
-static s4 *create_variable_map(inline_node *callee)
-{
-       s4 *varmap;
-       s4 i, t;
-       s4 varindex;
-       s4 n_javaindex;
-       s4 avail;
-       varinfo *v;
-
-       /* create the variable mapping */
-
-       varmap = DMNEW(s4, callee->jd->varcount);
-       for (i=0; i<callee->jd->varcount; ++i)
-               varmap[i] = -1;
-
-       /* translate local variables */
-
-       for (i=0; i<callee->m->maxlocals; ++i) {
-               for (t=0; t<5; ++t) {
-                       varindex = callee->jd->local_map[5*i + t];
-                       if (varindex == UNUSED)
-                               continue;
-
-                       v = &(callee->jd->var[varindex]);
-                       assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
-                       v->type = t; /* XXX restore if it is TYPE_VOID */
-
-                       avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
-
-                       if (avail == UNUSED) {
-                               avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, varindex);
-                               callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
-                       }
-
-                       varmap[varindex] = avail;
-               }
-       }
-
-       /* for synchronized instance methods we need an extra local */
-
-       if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
-               n_javaindex = callee->localsoffset - 1;
-               assert(n_javaindex >= 0);
-               assert(callee->parent);
-               assert(n_javaindex == callee->parent->localsoffset + callee->parent->m->maxlocals);
-
-               avail = callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR];
-
-               if (avail == UNUSED) {
-                       avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
-                       callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR] = avail;
-               }
-
-               callee->synclocal = avail;
-       }
-       else {
-               callee->synclocal = UNUSED;
-       }
-
-       return varmap;
-}
-
-
-/* basic block translation ****************************************************/
-
-#define INLINE_RETURN_REFERENCE(callee)  \
-       ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
-
-
-static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
-{
-       inline_target_ref *ref;
-
-       ref = DNEW(inline_target_ref);
-       ref->ref.block = blockp;
-       ref->isnumber = false;
-       ref->next = iln->refs;
-       iln->refs = ref;
-}
-
-
-#if 0
-static void inline_add_blocknr_reference(inline_node *iln, s4 *nrp)
-{
-       inline_target_ref *ref;
-
-       ref = DNEW(inline_target_ref);
-       ref->ref.nr = nrp;
-       ref->isnumber = true;
-       ref->next = iln->refs;
-       iln->refs = ref;
-}
-#endif
-
-
-static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
-{
-       inline_context *ctx;
-
-       ctx = iln->ctx;
-       assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
-
-       ctx->blockmap[ctx->blockmap_index].iln = iln;
-       ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
-       ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
-
-       ctx->blockmap_index++;
-}
-
-
-static basicblock * inline_map_block(inline_node *iln,
-                                                                        basicblock *o_block,
-                                                                        inline_node *targetiln)
-{
-       inline_block_map *bm;
-       inline_block_map *bmend;
-
-       assert(iln);
-       assert(targetiln);
-
-       if (!o_block)
-               return NULL;
-
-       bm = iln->ctx->blockmap;
-       bmend = bm + iln->ctx->blockmap_index;
-
-       while (bm < bmend) {
-               assert(bm->iln && bm->o_block && bm->n_block);
-               if (bm->o_block == o_block && bm->iln == targetiln)
-                       return bm->n_block;
-               bm++;
-       }
-
-       assert(false);
-       return NULL; /* not reached */
-}
-
-
-static void inline_resolve_block_refs(inline_target_ref **refs,
-                                                                         basicblock *o_bptr,
-                                                                         basicblock *n_bptr,
-                                                                         bool returnref)
-{
-       inline_target_ref *ref;
-       inline_target_ref *prev;
-
-       prev = NULL;
-       for (ref = *refs; ref != NULL; ref = ref->next) {
-               if (ref->isnumber && !returnref) {
-                       if (*(ref->ref.nr) == JAVALOCAL_FROM_RETADDR(o_bptr->nr)) {
-                               *(ref->ref.nr) = JAVALOCAL_FROM_RETADDR(n_bptr->nr);
-                               goto remove_ref;
-                       }
-               }
-               else {
-                       if (*(ref->ref.block) == o_bptr) {
-                               *(ref->ref.block) = n_bptr;
-                               goto remove_ref;
-                       }
-               }
-
-               /* skip this ref */
-
-               prev = ref;
-               continue;
-
-remove_ref:
-               /* remove this ref */
-
-               if (prev) {
-                       prev->next = ref->next;
-               }
-               else {
-                       *refs = ref->next;
-               }
-       }
-}
-
-
-/* basic block creation *******************************************************/
-
-static basicblock * create_block(inline_node *container,
-                                                                inline_node *iln,
-                                                                inline_node *inner,
-                                                                int indepth)
-{
-       basicblock  *n_bptr;
-       inline_node *outer;
-       s4           i;
-       s4           depth;
-       s4           varidx;
-       s4           newvaridx;
-
-       assert(container);
-       assert(iln);
-       assert(inner);
-       assert(indepth >= 0);
-
-       n_bptr = container->inlined_basicblocks_cursor++;
-       assert(n_bptr);
-       assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
-
-       BASICBLOCK_INIT(n_bptr, iln->m);
-
-       n_bptr->iinstr = container->inlined_iinstr_cursor;
-       n_bptr->next = n_bptr + 1;
-       n_bptr->nr = container->ctx->next_block_number++;
-       n_bptr->indepth = indepth;
-       n_bptr->flags = BBFINISHED; /* XXX */
-
-       /* set the inlineinfo of the new block */
-
-       if (iln->inline_start_instruction)
-               n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
-
-       if (indepth > container->ctx->maxinoutdepth)
-               container->ctx->maxinoutdepth = indepth;
-
-       if (indepth) {
-               n_bptr->invars = DMNEW(s4, indepth);
-
-
-               for (i=0; i<indepth; ++i)
-                       n_bptr->invars[i] = -1; /* XXX debug */
-
-               /* pass-through variables enter the block */
-
-               outer = inner->parent;
-               while (outer != NULL) {
-                       depth = outer->n_passthroughcount;
-
-                       assert(depth + inner->n_selfpassthroughcount <= indepth);
-
-                       for (i=0; i<inner->n_selfpassthroughcount; ++i) {
-                               varidx = inner->n_passthroughvars[i];
-                               newvaridx =
-                                       inline_new_variable_clone(container->ctx->resultjd,
-                                                                                         outer->jd,
-                                                                                         varidx);
-                               n_bptr->invars[depth + i] = newvaridx;
-                               outer->varmap[varidx] = newvaridx;
-                       }
-                       inner = outer;
-                       outer = outer->parent;
-               }
-       }
-       else {
-               n_bptr->invars = NULL;
-       }
-
-       /* XXX for the verifier. should not be here */
-
-       {
-               varinfo *dv;
-
-               dv = DMNEW(varinfo, iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
-               MZERO(dv, varinfo,  iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
-               n_bptr->inlocals = dv;
-       }
-
-       return n_bptr;
-}
-
-
-static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
-{
-       s4 *jl;
-       s4 i, j;
-
-       jl = DMNEW(s4, iln->jd->maxlocals);
-
-       for (i=0; i<iln->jd->maxlocals; ++i) {
-               j = javalocals[i];
-               if (j > UNUSED)
-                       j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
-               jl[i] = j;
-
-#if 0
-               if (j < UNUSED) {
-                       /* an encoded returnAddress value - must be relocated */
-                       inline_add_blocknr_reference(iln, &(jl[i]));
-               }
-#endif
-       }
-
-       return jl;
-}
-
-
-static basicblock * create_body_block(inline_node *iln,
-                                                                         basicblock *o_bptr, s4 *varmap)
-{
-       basicblock *n_bptr;
-       s4 i;
-
-       n_bptr = create_block(iln, iln, iln,
-                                                 o_bptr->indepth + iln->n_passthroughcount);
-
-       n_bptr->type = o_bptr->type;
-       n_bptr->flags = o_bptr->flags;
-       n_bptr->bitflags = o_bptr->bitflags;
-
-       /* resolve references to this block */
-
-       inline_resolve_block_refs(&(iln->refs), o_bptr, n_bptr, false);
-
-       /* translate the invars of the original block */
-
-       for (i=0; i<o_bptr->indepth; ++i) {
-               n_bptr->invars[iln->n_passthroughcount + i] =
-                       inline_translate_variable(iln->ctx->resultjd, iln->jd,
-                               varmap,
-                               o_bptr->invars[i]);
-       }
-
-       /* translate javalocals info (not for dead code) */
-
-       if (n_bptr->flags >= BBREACHED)
-               n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
-
-       return n_bptr;
-}
-
-
-static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
-{
-       basicblock *n_bptr;
-       s4 retcount;
-       s4 idx;
-
-       /* number of return variables */
-
-       retcount = (callee->n_resultlocal == -1
-                               && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
-
-       /* start the epilog block */
-
-       n_bptr = create_block(caller, caller, callee,
-                                                 callee->n_passthroughcount + retcount);
-
-       /* resolve references to the return block */
-
-       inline_resolve_block_refs(&(callee->refs),
-                                                         INLINE_RETURN_REFERENCE(callee),
-                                                         n_bptr,
-                                                         true);
-
-       /* return variable */
-
-       if (retcount) {
-               idx = inline_new_variable(caller->ctx->resultjd,
-                          callee->m->parseddesc->returntype.type, 0 /* XXX */);
-               n_bptr->invars[callee->n_passthroughcount] = idx;
-               varmap[callee->callerins->dst.varindex] = idx;
-       }
-
-       /* set javalocals */
-
-       n_bptr->javalocals = DMNEW(s4, caller->jd->maxlocals);
-       MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
-
-       /* set block flags & type */
-
-       n_bptr->flags = /* XXX original block flags */ BBFINISHED;
-       n_bptr->type = BBTYPE_STD;
-
-       return n_bptr;
-}
-
-
-static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
-{
-       inline_node *outer;
-       s4           i;
-       s4           depth;
-       s4           varidx;
-
-       n_bptr->outdepth = outdepth;
-       n_bptr->outvars = DMNEW(s4, outdepth);
-
-       for (i=0; i<outdepth; ++i)
-               n_bptr->outvars[i] = 0; /* XXX debug */
-
-       if (outdepth > iln->ctx->maxinoutdepth)
-               iln->ctx->maxinoutdepth = outdepth;
-
-       /* pass-through variables leave the block */
-
-       outer = inner->parent;
-       while (outer != NULL) {
-               depth = outer->n_passthroughcount;
-
-               assert(depth + inner->n_selfpassthroughcount <= outdepth);
-
-               for (i=0; i<inner->n_selfpassthroughcount; ++i) {
-                       varidx = inner->n_passthroughvars[i];
-                       n_bptr->outvars[depth + i] =
-                               inline_translate_variable(iln->ctx->resultjd,
-                                                                                 outer->jd,
-                                                                                 outer->varmap,
-                                                                                 varidx);
-               }
-               inner = outer;
-               outer = outer->parent;
-       }
-}
-
-
-static void close_prolog_block(inline_node *iln,
-                                                          basicblock *n_bptr,
-                                                          inline_node *nextcall)
-{
-       /* XXX add original outvars! */
-       close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
-
-       /* pass-through variables */
-
-       DOLOG( printf("closed prolog block:\n");
-                  show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
-}
-
-
-static void close_body_block(inline_node *iln,
-                                                        basicblock *n_bptr,
-                                                        basicblock *o_bptr,
-                                                        s4 *varmap,
-                                                        s4 retcount,
-                                                        s4 retidx)
-{
-       s4 i;
-
-       close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
-
-       /* translate the outvars of the original block */
-
-       /* XXX reuse code */
-       for (i=0; i<o_bptr->outdepth; ++i) {
-               n_bptr->outvars[iln->n_passthroughcount + i] =
-                       inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
-                                       o_bptr->outvars[i]);
-       }
-
-       /* set the return variable, if any */
-
-       if (retcount) {
-               assert(retidx >= 0);
-               n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
-       }
-}
-
-
-/* inlined code generation ****************************************************/
-
-static instruction * inline_instruction(inline_node *iln,
-                                                                               s4 opcode,
-                                                                               instruction *o_iptr)
-{
-       instruction *n_iptr;
-
-       n_iptr = (iln->inlined_iinstr_cursor++);
-       assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
-
-       n_iptr->opc = opcode;
-       n_iptr->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
-       n_iptr->line = o_iptr->line;
-
-       return n_iptr;
-}
-
-static void inline_generate_sync_builtin(inline_node *iln,
-                                                                                inline_node *callee,
-                                                                                instruction *o_iptr,
-                                                                                s4 instancevar,
-                                                                                functionptr func)
-{
-       int          syncvar;
-       instruction *n_ins;
-
-       if (callee->m->flags & ACC_STATIC) {
-               /* ACONST */
-               syncvar = inline_new_temp_variable(iln->ctx->resultjd, TYPE_ADR);
-
-               n_ins = inline_instruction(iln, ICMD_ACONST, o_iptr);
-               n_ins->sx.val.c.cls = callee->m->clazz;
-               n_ins->dst.varindex = syncvar;
-               n_ins->flags.bits |= INS_FLAG_CLASS;
-       }
-       else {
-               syncvar = instancevar;
-       }
-
-       assert(syncvar != UNUSED);
-
-       /* MONITORENTER / MONITOREXIT */
-
-       n_ins = inline_instruction(iln, ICMD_BUILTIN, o_iptr);
-       n_ins->sx.s23.s3.bte = builtintable_get_internal(func);
-       n_ins->s1.argcount = 1; /* XXX add through-vars */
-       n_ins->sx.s23.s2.args = DMNEW(s4, 1);
-       n_ins->sx.s23.s2.args[0] = syncvar;
-}
-
-static s4 emit_inlining_prolog(inline_node *iln,
-                                                          inline_node *callee,
-                                                          instruction *o_iptr,
-                                                          s4 *varmap)
-{
-       methodinfo *calleem;
-       methoddesc *md;
-       int i;
-       int localindex;
-       int type;
-       instruction *n_ins;
-       insinfo_inline *insinfo;
-       s4 varindex;
-
-       assert(iln && callee && o_iptr);
-
-       calleem = callee->m;
-       md = calleem->parseddesc;
-
-       /* INLINE_START instruction */
-
-       n_ins = inline_instruction(iln, ICMD_INLINE_START, o_iptr);
-
-       insinfo = DNEW(insinfo_inline);
-       insinfo->method = callee->m;
-       insinfo->outer = iln->m;
-       insinfo->synclocal = callee->synclocal;
-       insinfo->synchronize = callee->synchronize;
-       insinfo->javalocals_start = NULL;
-       insinfo->javalocals_end = NULL;
-
-       /* info about stack vars live at the INLINE_START */
-
-       insinfo->throughcount = callee->n_passthroughcount;
-       insinfo->paramcount = md->paramcount;
-       insinfo->stackvarscount = o_iptr->s1.argcount;
-       insinfo->stackvars = DMNEW(s4, insinfo->stackvarscount);
-       for (i=0; i<insinfo->stackvarscount; ++i)
-               insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[i]];
-
-       /* info about the surrounding inlining */
-
-       if (iln->inline_start_instruction)
-               insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
-       else
-               insinfo->parent = NULL;
-
-       /* finish the INLINE_START instruction */
-
-       n_ins->sx.s23.s3.inlineinfo = insinfo;
-       callee->inline_start_instruction = n_ins;
-
-       DOLOG( printf("%sprolog: ", iln->indent);
-                  show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
-
-       /* handle parameters for the inlined callee */
-
-       localindex = callee->localsoffset + md->paramslots;
-
-       for (i=md->paramcount-1; i>=0; --i) {
-               assert(iln);
-
-               type = md->paramtypes[i].type;
-
-               localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
-               assert(callee->regdata);
-
-               /* translate the argument variable */
-
-               varindex = varmap[o_iptr->sx.s23.s2.args[i]];
-               assert(varindex != UNUSED);
-
-               /* remove preallocation from the argument variable */
-
-               iln->ctx->resultjd->var[varindex].flags &= ~(PREALLOC | INMEMORY);
-
-               /* check the instance slot against NULL */
-               /* we don't need that for <init> methods, as the verifier  */
-               /* ensures that they are only called for an uninit. object */
-               /* (which may not be NULL).                                */
-
-               if (!callee->isstatic && i == 0 && calleem->name != utf_init) {
-                       assert(type == TYPE_ADR);
-                       n_ins = inline_instruction(iln, ICMD_CHECKNULL, o_iptr);
-                       n_ins->s1.varindex = varindex;
-                       n_ins->dst.varindex = n_ins->s1.varindex;
-               }
-
-               /* store argument into local variable of inlined callee */
-
-               if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
-               {
-                       /* this value is used in the callee */
-
-                       if (i == 0 && callee->synclocal != UNUSED) {
-                               /* we also need it for synchronization, so copy it */
-                               assert(type == TYPE_ADR);
-                               n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
-                       }
-                       else {
-                               n_ins = inline_instruction(iln, ICMD_ISTORE + type, o_iptr);
-                               n_ins->sx.s23.s3.javaindex = UNUSED;
-                       }
-                       n_ins->s1.varindex = varindex;
-                       n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
-                       assert(n_ins->dst.varindex != UNUSED);
-               }
-               else if (i == 0 && callee->synclocal != UNUSED) {
-                       /* the value is not used inside the callee, but we need it for */
-                       /* synchronization                                             */
-                       /* XXX In this case it actually makes no sense to create a     */
-                       /*     separate synchronization variable.                      */
-
-                       n_ins = inline_instruction(iln, ICMD_NOP, o_iptr);
-               }
-               else {
-                       /* this value is not used, pop it */
-
-                       n_ins = inline_instruction(iln, ICMD_POP, o_iptr);
-                       n_ins->s1.varindex = varindex;
-               }
-
-               DOLOG( printf("%sprolog: ", iln->indent);
-                          show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
-       }
-
-       /* COPY for synchronized instance methods */
-
-       if (callee->synclocal != UNUSED) {
-               n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
-               n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
-               n_ins->dst.varindex = callee->synclocal;
-
-               assert(n_ins->s1.varindex != UNUSED);
-       }
-
-       if (callee->synchronize) {
-               inline_generate_sync_builtin(iln, callee, o_iptr,
-                                                                        (callee->isstatic) ? UNUSED : varmap[o_iptr->sx.s23.s2.args[0]],
-                                                                        LOCK_monitor_enter);
-       }
-
-       /* INLINE_BODY instruction */
-
-       n_ins = inline_instruction(iln, ICMD_INLINE_BODY, callee->jd->basicblocks[0].iinstr);
-       n_ins->sx.s23.s3.inlineinfo = insinfo;
-
-       return 0; /* XXX */
-}
-
-
-static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
-{
-       instruction *n_ins;
-       s4          *jl;
-
-       assert(iln && callee && o_iptr);
-       assert(callee->inline_start_instruction);
-
-       if (callee->synchronize) {
-               inline_generate_sync_builtin(iln, callee, o_iptr,
-                                                                        callee->synclocal,
-                                                                        LOCK_monitor_exit);
-       }
-
-       /* INLINE_END instruction */
-
-       n_ins = inline_instruction(iln, ICMD_INLINE_END, o_iptr);
-       n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
-
-       /* set the javalocals */
-
-       jl = DMNEW(s4, iln->jd->maxlocals);
-       MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
-       n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
-
-       DOLOG( printf("%sepilog: ", iln->indent);
-                  show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
-}
-
-
-#define TRANSLATE_VAROP(vo)  \
-       n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
-
-
-static void inline_clone_instruction(inline_node *iln,
-                                                                        jitdata *jd,
-                                                                        jitdata *origjd,
-                                                                        s4 *varmap,
-                                                                        instruction *o_iptr,
-                                                                        instruction *n_iptr)
-{
-       icmdtable_entry_t *icmdt;
-       builtintable_entry *bte;
-       methoddesc *md;
-       s4 i, j;
-       branch_target_t *table;
-       lookup_target_t *lookup;
-       inline_node *scope;
-
-       *n_iptr = *o_iptr;
-
-       icmdt = &(icmd_table[o_iptr->opc]);
-
-       switch (icmdt->dataflow) {
-               case DF_0_TO_0:
-                       break;
-
-               case DF_3_TO_0:
-                       TRANSLATE_VAROP(sx.s23.s3);
-               case DF_2_TO_0:
-                       TRANSLATE_VAROP(sx.s23.s2);
-               case DF_1_TO_0:
-                       TRANSLATE_VAROP(s1);
-                       break;
-
-               case DF_2_TO_1:
-                       TRANSLATE_VAROP(sx.s23.s2);
-               case DF_1_TO_1:
-               case DF_COPY:
-               case DF_MOVE:
-                       TRANSLATE_VAROP(s1);
-               case DF_0_TO_1:
-                       TRANSLATE_VAROP(dst);
-                       break;
-
-               case DF_N_TO_1:
-                       n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
-                       for (i=0; i<n_iptr->s1.argcount; ++i) {
-                               n_iptr->sx.s23.s2.args[i] =
-                                       inline_translate_variable(jd, origjd, varmap,
-                                                       o_iptr->sx.s23.s2.args[i]);
-                       }
-                       TRANSLATE_VAROP(dst);
-                       break;
-
-               case DF_INVOKE:
-                       INSTRUCTION_GET_METHODDESC(n_iptr, md);
-clone_call:
-                       n_iptr->s1.argcount += iln->n_passthroughcount;
-                       n_iptr->sx.s23.s2.args = DMNEW(s4, n_iptr->s1.argcount);
-                       for (i=0; i<o_iptr->s1.argcount; ++i) {
-                               n_iptr->sx.s23.s2.args[i] =
-                                       inline_translate_variable(jd, origjd, varmap,
-                                                       o_iptr->sx.s23.s2.args[i]);
-                       }
-                       for (scope = iln; scope != NULL; scope = scope->parent) {
-                               for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
-                                       n_iptr->sx.s23.s2.args[i++] =
-                                               scope->parent->varmap[scope->n_passthroughvars[j]];
-                               }
-                       }
-                       if (md->returntype.type != TYPE_VOID)
-                               TRANSLATE_VAROP(dst);
-                       break;
-
-               case DF_BUILTIN:
-                       bte = n_iptr->sx.s23.s3.bte;
-                       md = bte->md;
-                       goto clone_call;
-
-               default:
-                       assert(0);
-       }
-
-       switch (icmdt->controlflow) {
-               case CF_RET:
-                       TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
-                       /* FALLTHROUGH */
-               case CF_IF:
-               case CF_GOTO:
-                       inline_add_block_reference(iln, &(n_iptr->dst.block));
-                       break;
-
-               case CF_JSR:
-                       inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
-                       break;
-
-               case CF_TABLE:
-                       i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
-
-                       table = DMNEW(branch_target_t, i);
-                       MCOPY(table, o_iptr->dst.table, branch_target_t, i);
-                       n_iptr->dst.table = table;
-
-                       while (--i >= 0) {
-                               inline_add_block_reference(iln, &(table->block));
-                               table++;
-                       }
-                       break;
-
-               case CF_LOOKUP:
-                       inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
-
-                       i = n_iptr->sx.s23.s2.lookupcount;
-                       lookup = DMNEW(lookup_target_t, i);
-                       MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
-                       n_iptr->dst.lookup = lookup;
-
-                       while (--i >= 0) {
-                               inline_add_block_reference(iln, &(lookup->target.block));
-                               lookup++;
-                       }
-                       break;
-       }
-
-       /* XXX move this to dataflow section? */
-
-       switch (n_iptr->opc) {
-               case ICMD_ASTORE:
-#if 0
-                       if (n_iptr->flags.bits & INS_FLAG_RETADDR)
-                               inline_add_blocknr_reference(iln, &(n_iptr->sx.s23.s2.retaddrnr));
-#endif
-                       /* FALLTHROUGH! */
-               case ICMD_ISTORE:
-               case ICMD_LSTORE:
-               case ICMD_FSTORE:
-               case ICMD_DSTORE:
-                       stack_javalocals_store(n_iptr, iln->javalocals);
-                       break;
-       }
-}
-
-
-static void inline_rewrite_method(inline_node *iln)
-{
-       basicblock *o_bptr;
-       s4 len;
-       instruction *o_iptr;
-       instruction *n_iptr;
-       inline_node *nextcall;
-       basicblock *n_bptr;
-       inline_block_map *bm;
-       int i;
-       int icount;
-       jitdata *resultjd;
-       jitdata *origjd;
-       char indent[100]; /* XXX debug */
-       s4 retcount;
-       s4 retidx;
-
-       assert(iln);
-
-       resultjd = iln->ctx->resultjd;
-       origjd = iln->jd;
-
-       n_bptr = NULL;
-       nextcall = iln->children;
-
-       /* XXX debug */
-       for (i=0; i<iln->depth; ++i)
-               indent[i] = '\t';
-       indent[i] = 0;
-       iln->indent = indent;
-
-       DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
-                  printf("%s(passthrough: %d+%d)\n",
-                               indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
-                               iln->n_passthroughcount); );
-
-       /* set memory cursors */
-
-       iln->inlined_iinstr_cursor = iln->inlined_iinstr;
-       iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
-
-       /* allocate temporary buffers */
-
-       iln->javalocals = DMNEW(s4, iln->jd->maxlocals);
-
-       /* loop over basic blocks */
-
-       o_bptr = iln->jd->basicblocks;
-       for (; o_bptr; o_bptr = o_bptr->next) {
-
-               if (o_bptr->flags < BBREACHED) {
-
-                       /* ignore the dummy end block */
-
-                       if (o_bptr->icount == 0 && o_bptr->next == NULL) {
-                               /* enter the following block as translation, for exception handler ranges */
-                               inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
-                               continue;
-                       }
-
-                       DOLOG(
-                       printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
-                                       indent,
-                                       o_bptr->nr, o_bptr->flags, o_bptr->type,
-                                       o_bptr->indepth);
-                       method_println(iln->m);
-                       );
-
-                       n_bptr = create_body_block(iln, o_bptr, iln->varmap);
-
-                       /* enter it in the blockmap */
-
-                       inline_block_translation(iln, o_bptr, n_bptr);
-
-                       close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
-                       continue;
-               }
-
-               len = o_bptr->icount;
-               o_iptr = o_bptr->iinstr;
-
-               DOLOG(
-               printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
-                               indent,
-                               o_bptr->nr, o_bptr->flags, o_bptr->type,
-                               o_bptr->indepth);
-               method_println(iln->m);
-               show_basicblock(iln->jd, o_bptr, SHOW_STACK);
-               );
-
-               if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
-                       /* create an inlined clone of this block */
-
-                       n_bptr = create_body_block(iln, o_bptr, iln->varmap);
-                       icount = 0;
-
-                       /* enter it in the blockmap */
-
-                       inline_block_translation(iln, o_bptr, n_bptr);
-
-                       /* initialize the javalocals */
-
-                       MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
-               }
-               else {
-                       s4 *jl;
-
-                       /* continue caller block */
-
-                       n_bptr = iln->inlined_basicblocks_cursor - 1;
-                       icount = n_bptr->icount;
-
-                       /* translate the javalocals */
-
-                       jl = translate_javalocals(iln, o_bptr->javalocals);
-                       iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
-
-                       MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
-               }
-
-               /* iterate over the ICMDs of this block */
-
-               retcount = 0;
-               retidx = UNUSED;
-
-               while (--len >= 0) {
-
-                       DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false,  SHOW_STACK);
-                                  printf("\n") );
-
-                       /* handle calls that will be inlined */
-
-                       if (nextcall && o_iptr == nextcall->callerins) {
-
-                               /* write the inlining prolog */
-
-                               (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
-                               icount += nextcall->prolog_instructioncount;
-
-                               /* end current block, or glue blocks together */
-
-                               n_bptr->icount = icount;
-
-                               if (nextcall->blockbefore) {
-                                       close_prolog_block(iln, n_bptr, nextcall);
-                               }
-                               else {
-                                       /* XXX */
-                               }
-
-                               /* check if the result is a local variable */
-
-                               if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
-                                               && o_iptr->dst.varindex < iln->jd->localcount)
-                               {
-                                       nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
-                               }
-                               else
-                                       nextcall->n_resultlocal = -1;
-
-                               /* set memory pointers in the callee */
-
-                               nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
-                               nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
-
-                               /* recurse */
-
-                               DOLOG( printf("%sentering inline ", indent);
-                                          show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
-
-                               inline_rewrite_method(nextcall);
-
-                               DOLOG( printf("%sleaving inline ", indent);
-                                          show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
-
-                               /* update memory cursors */
-
-                               assert(nextcall->inlined_iinstr_cursor
-                                               <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
-                               assert(nextcall->inlined_basicblocks_cursor
-                                               == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
-                               iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
-                               iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
-
-                               /* start new block, or glue blocks together */
-
-                               if (nextcall->blockafter) {
-                                       n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
-                                       icount = 0;
-                               }
-                               else {
-                                       n_bptr = iln->inlined_basicblocks_cursor - 1;
-                                       icount = n_bptr->icount;
-                                       /* XXX */
-                               }
-
-                               /* emit inlining epilog */
-
-                               emit_inlining_epilog(iln, nextcall, o_iptr);
-                               icount += nextcall->epilog_instructioncount;
-
-                               /* proceed to next call */
-
-                               nextcall = nextcall->next;
-                       }
-                       else {
-                               n_iptr = (iln->inlined_iinstr_cursor++);
-                               assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
-
-                               switch (o_iptr->opc) {
-                                       case ICMD_RETURN:
-                                               if (iln->depth == 0)
-                                                       goto default_clone;
-                                               goto return_tail;
-
-                                       case ICMD_IRETURN:
-                                       case ICMD_ARETURN:
-                                       case ICMD_LRETURN:
-                                       case ICMD_FRETURN:
-                                       case ICMD_DRETURN:
-                                               if (iln->depth == 0)
-                                                       goto default_clone;
-                                               retcount = 1;
-                                               retidx = iln->varmap[o_iptr->s1.varindex];
-                                               if (iln->n_resultlocal != -1) {
-                                                       /* store result in a local variable */
-
-                                                       DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
-                                                       /* This relies on the same sequence of types for */
-                                                       /* ?STORE and ?RETURN opcodes.                   */
-                                                       n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
-                                                       n_iptr->s1.varindex = retidx;
-                                                       n_iptr->dst.varindex = iln->n_resultlocal;
-                                                       n_iptr->sx.s23.s3.javaindex = UNUSED; /* XXX set real javaindex? */
-
-                                                       retcount = 0;
-                                                       retidx = UNUSED;
-
-                                                       n_iptr = (iln->inlined_iinstr_cursor++);
-                                                       assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
-                                                       icount++;
-                                               }
-                                               else if ((retidx < resultjd->localcount && iln->blockafter)
-                                                               || !iln->blockafter) /* XXX do we really always need the MOVE? */
-                                               {
-                                                       /* local must not become outvar, insert a MOVE */
-
-                                                       n_iptr->opc = ICMD_MOVE;
-                                                       n_iptr->s1.varindex = retidx;
-                                                       retidx = inline_new_temp_variable(resultjd,
-                                                                                                                         resultjd->var[retidx].type);
-                                                       n_iptr->dst.varindex = retidx;
-
-                                                       n_iptr = (iln->inlined_iinstr_cursor++);
-                                                       assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
-                                                       icount++;
-                                               }
-return_tail:
-                                               if (iln->blockafter) {
-                                                       n_iptr->opc = ICMD_GOTO;
-                                                       n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
-                                                       inline_add_block_reference(iln, &(n_iptr->dst.block));
-                                               }
-                                               else {
-                                                       n_iptr->opc = ICMD_NOP;
-                                               }
-                                               break;
-#if 0
-                                               if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
-                                                       n_iptr->opc = ICMD_NOP;
-                                                       break;
-                                               }
-                                               goto default_clone;
-                                               break;
-#endif
-
-                                       default:
-default_clone:
-                                               inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
-                               }
-
-                               DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
-                                          printf("\n"););
-
-                               icount++;
-                       }
-
-                       o_iptr++;
-               }
-
-               /* end of basic block */
-
-               if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
-                       close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
-                       n_bptr->icount = icount;
-
-                       DOLOG( printf("closed body block:\n");
-                                  show_basicblock(resultjd, n_bptr, SHOW_STACK); );
-               }
-               else {
-                       n_bptr->icount = icount;
-                       assert(iln->parent);
-                       if (retidx != UNUSED)
-                               iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
-               }
-       }
-
-       bm = iln->ctx->blockmap;
-       for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
-               assert(bm->iln && bm->o_block && bm->n_block);
-               if (bm->iln == iln)
-                       inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block, false);
-       }
-
-#if !defined(NDEBUG)
-       if (iln->refs) {
-               inline_target_ref *ref;
-               ref = iln->refs;
-               while (ref) {
-                       if (!iln->depth || ref->isnumber || *(ref->ref.block) != INLINE_RETURN_REFERENCE(iln)) {
-                               DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
-                                          (void*)*(ref->ref.block)) );
-                               assert(false);
-                       }
-                       ref = ref->next;
-               }
-       }
-#endif
-}
-
-
-static exception_entry * inline_exception_tables(inline_node *iln,
-                                                                                                exception_entry *n_extable,
-                                                                                                exception_entry **prevextable)
-{
-       inline_node *child;
-       inline_node *scope;
-       exception_entry *et;
-
-       assert(iln);
-       assert(n_extable);
-       assert(prevextable);
-
-       child = iln->children;
-       if (child) {
-               do {
-                       n_extable = inline_exception_tables(child, n_extable, prevextable);
-                       child = child->next;
-               } while (child != iln->children);
-       }
-
-       et = iln->jd->exceptiontable;
-       for (; et != NULL; et = et->down) {
-               assert(et);
-               MZERO(n_extable, exception_entry, 1);
-               n_extable->start     = inline_map_block(iln, et->start  , iln);
-               n_extable->end       = inline_map_block(iln, et->end    , iln);
-               n_extable->handler   = inline_map_block(iln, et->handler, iln);
-               n_extable->catchtype = et->catchtype;
-
-               if (*prevextable) {
-                       (*prevextable)->down = n_extable;
-               }
-               *prevextable = n_extable;
-
-               n_extable++;
-       }
-
-       if (iln->handler_monitorexit) {
-               exception_entry **activehandlers;
-
-               MZERO(n_extable, exception_entry, 1);
-               n_extable->start   = iln->inlined_basicblocks;
-               n_extable->end     = iln->inlined_basicblocks_cursor;
-               n_extable->handler = iln->handler_monitorexit;
-               n_extable->catchtype.any = NULL; /* finally */
-
-               if (*prevextable) {
-                       (*prevextable)->down = n_extable;
-               }
-               *prevextable = n_extable;
-
-               n_extable++;
-
-               /* We have to protect the created handler with the same handlers */
-               /* that protect the method body itself.                          */
-
-               for (scope = iln; scope->parent != NULL; scope = scope->parent) {
-
-                       activehandlers = scope->o_handlers;
-                       assert(activehandlers);
-
-                       while (*activehandlers) {
-
-                               assert(scope->parent);
-
-                               MZERO(n_extable, exception_entry, 1);
-                               n_extable->start     = iln->handler_monitorexit;
-                               n_extable->end       = iln->handler_monitorexit + 1; /* XXX ok in this case? */
-                               n_extable->handler   = inline_map_block(scope->parent,
-                                                                                                               (*activehandlers)->handler,
-                                                                                                               scope->parent);
-                               n_extable->catchtype = (*activehandlers)->catchtype;
-
-                               if (*prevextable) {
-                                       (*prevextable)->down = n_extable;
-                               }
-                               *prevextable = n_extable;
-
-                               n_extable++;
-                               activehandlers++;
-                       }
-               }
-       }
-
-       return n_extable;
-}
-
-
-static void inline_locals(inline_node *iln)
-{
-       inline_node *child;
-
-       assert(iln);
-
-       iln->varmap = create_variable_map(iln);
-
-       child = iln->children;
-       if (child) {
-               do {
-                       inline_locals(child);
-                       child = child->next;
-               } while (child != iln->children);
-       }
-
-       if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
-               iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
-       if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
-               iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
-       if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
-               iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
-}
-
-
-static void inline_interface_variables(inline_node *iln)
-{
-       basicblock *bptr;
-       jitdata *resultjd;
-       s4 i;
-       varinfo *v;
-
-       resultjd = iln->ctx->resultjd;
-
-       resultjd->interface_map = DMNEW(interface_info, 5*iln->ctx->maxinoutdepth);
-       for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
-               resultjd->interface_map[i].flags = UNUSED;
-
-       for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
-               assert(bptr->indepth  <= iln->ctx->maxinoutdepth);
-               assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
-
-               for (i=0; i<bptr->indepth; ++i) {
-                       v = &(resultjd->var[bptr->invars[i]]);
-                       v->flags |= INOUT;
-                       if (v->type == TYPE_RET)
-                               v->flags |= PREALLOC;
-                       else
-                               v->flags &= ~PREALLOC;
-                       v->flags &= ~INMEMORY;
-                       assert(bptr->invars[i] >= resultjd->localcount);
-
-                       if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
-                               resultjd->interface_map[5*i + v->type].flags = v->flags;
-                       }
-                       else {
-                               resultjd->interface_map[5*i + v->type].flags |= v->flags;
-                       }
-               }
-
-               for (i=0; i<bptr->outdepth; ++i) {
-                       v = &(resultjd->var[bptr->outvars[i]]);
-                       v->flags |= INOUT;
-                       if (v->type == TYPE_RET)
-                               v->flags |= PREALLOC;
-                       else
-                               v->flags &= ~PREALLOC;
-                       v->flags &= ~INMEMORY;
-                       assert(bptr->outvars[i] >= resultjd->localcount);
-
-                       if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
-                               resultjd->interface_map[5*i + v->type].flags = v->flags;
-                       }
-                       else {
-                               resultjd->interface_map[5*i + v->type].flags |= v->flags;
-                       }
-               }
-       }
-}
-
-
-static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
-{
-       basicblock *n_bptr;
-       instruction *n_ins;
-       inline_node *child;
-       builtintable_entry *bte;
-       s4 exvar;
-       s4 syncvar;
-       s4 i;
-
-       child = iln->children;
-       if (child) {
-               do {
-                       inline_write_exception_handlers(master, child);
-                       child = child->next;
-               } while (child != iln->children);
-       }
-
-       if (iln->synchronize) {
-               /* create the monitorexit handler */
-               n_bptr = create_block(master, iln, iln,
-                                                         iln->n_passthroughcount + 1);
-               n_bptr->type = BBTYPE_EXH;
-               n_bptr->flags = BBFINISHED;
-
-               exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
-               n_bptr->invars[iln->n_passthroughcount] = exvar;
-
-               iln->handler_monitorexit = n_bptr;
-
-               /* ACONST / ALOAD */
-
-               n_ins = master->inlined_iinstr_cursor++;
-               if (iln->m->flags & ACC_STATIC) {
-                       n_ins->opc = ICMD_ACONST;
-                       n_ins->sx.val.c.cls = iln->m->clazz;
-                       n_ins->flags.bits = INS_FLAG_CLASS;
-               }
-               else {
-                       n_ins->opc = ICMD_ALOAD;
-                       n_ins->s1.varindex = iln->synclocal;
-                       assert(n_ins->s1.varindex != UNUSED);
-               }
-               /* XXX could be PREALLOCed for  builtin call */
-               syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
-               n_ins->dst.varindex = syncvar;
-               n_ins->line = 0;
-
-               /* MONITOREXIT */
-
-               bte = builtintable_get_internal(LOCK_monitor_exit);
-
-               n_ins = master->inlined_iinstr_cursor++;
-               n_ins->opc = ICMD_BUILTIN;
-               n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
-               n_ins->sx.s23.s2.args = DMNEW(s4, n_ins->s1.argcount);
-               n_ins->sx.s23.s2.args[0] = syncvar;
-               for (i=0; i < iln->n_passthroughcount + 1; ++i) {
-                       n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
-               }
-               n_ins->sx.s23.s3.bte = bte;
-               n_ins->line = 0;
-
-               /* ATHROW */
-
-               n_ins = master->inlined_iinstr_cursor++;
-               n_ins->opc = ICMD_ATHROW;
-               n_ins->flags.bits = 0;
-               n_ins->s1.varindex = exvar;
-               n_ins->line = 0;
-
-               /* close basic block */
-
-               close_block(iln, iln, n_bptr, iln->n_passthroughcount);
-               n_bptr->icount = 3;
-       }
-}
-
-
-/* second pass driver *********************************************************/
-
-static bool inline_transform(inline_node *iln, jitdata *jd)
-{
-       instruction *n_ins;
-       basicblock *n_bb;
-       basicblock *n_bptr;
-       exception_entry *n_ext;
-       exception_entry *prevext;
-       codegendata *n_cd;
-       jitdata *n_jd;
-       s4 i;
-#if defined(INLINE_VERIFY_RESULT)
-       static int debug_verify_inlined_code = 1;
-#endif
-#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
-       static int debug_counter = 0;
-#endif
-
-       DOLOG( dump_inline_tree(iln, 0); );
-
-       assert(iln && jd);
-
-       n_ins = DMNEW(instruction, iln->cumul_instructioncount);
-       MZERO(n_ins, instruction, iln->cumul_instructioncount);
-       iln->inlined_iinstr = n_ins;
-
-       n_bb = DMNEW(basicblock, iln->cumul_basicblockcount);
-       MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
-       iln->inlined_basicblocks = n_bb;
-
-       iln->ctx->blockmap = DMNEW(inline_block_map, iln->cumul_blockmapcount);
-
-       n_jd = jit_jitdata_new(iln->m);
-       n_jd->flags = jd->flags;
-       n_jd->code->optlevel = jd->code->optlevel;
-       iln->ctx->resultjd = n_jd;
-
-       reg_setup(n_jd);
-
-       /* create the local_map */
-
-       n_jd->local_map = DMNEW(s4, 5*iln->cumul_maxlocals);
-       for (i=0; i<5*iln->cumul_maxlocals; ++i)
-               n_jd->local_map[i] = UNUSED;
-
-       /* create / coalesce local variables */
-
-       n_jd->varcount = 0;
-       n_jd->vartop = 0;
-       n_jd->var = NULL;
-
-       inline_locals(iln);
-
-       n_jd->localcount = n_jd->vartop;
-
-       /* extra variables for verification (debugging) */
-
-#if defined(INLINE_VERIFY_RESULT)
-       if (debug_verify_inlined_code) {
-               n_jd->vartop   += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
-               if (n_jd->vartop > n_jd->varcount) {
-                       /* XXX why? */
-                       n_jd->var = DMREALLOC(n_jd->var, varinfo, n_jd->varcount, n_jd->vartop);
-                       n_jd->varcount = n_jd->vartop;
-               }
-       }
-#endif /* defined(INLINE_VERIFY_RESULT) */
-
-       /* write inlined code */
-
-       inline_rewrite_method(iln);
-
-       /* create exception handlers */
-
-       inline_write_exception_handlers(iln, iln);
-
-       /* write the dummy end block */
-
-       n_bptr = create_block(iln, iln, iln, 0);
-       n_bptr->flags = BBUNDEF;
-       n_bptr->type = BBTYPE_STD;
-
-       /* store created code in jitdata */
-
-       n_jd->basicblocks = iln->inlined_basicblocks;
-       n_jd->instructioncount = iln->cumul_instructioncount;
-       n_jd->instructions = iln->inlined_iinstr;
-
-       /* link the basic blocks (dummy end block is not counted) */
-
-       n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
-       for (i=0; i<n_jd->basicblockcount + 1; ++i)
-               n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
-       if (i)
-               n_jd->basicblocks[i-1].next = NULL;
-
-       /* check basicblock numbers */
-
-#if !defined(NDEBUG)
-       jit_check_basicblock_numbers(n_jd);
-#endif
-
-       /* create the exception table */
-
-       if (iln->cumul_exceptiontablelength) {
-               exception_entry *tableend;
-
-               n_ext = DMNEW(exception_entry, iln->cumul_exceptiontablelength);
-               prevext = NULL;
-               tableend = inline_exception_tables(iln, n_ext, &prevext);
-               assert(tableend == n_ext + iln->cumul_exceptiontablelength);
-               if (prevext)
-                       prevext->down = NULL;
-
-               n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
-               n_jd->exceptiontable = n_ext;
-       }
-       else {
-               n_ext = NULL;
-       }
-
-       /*******************************************************************************/
-
-       n_cd = n_jd->cd;
-       memcpy(n_cd, jd->cd, sizeof(codegendata));
-
-       n_cd->method = NULL; /* XXX */
-       n_jd->maxlocals = iln->cumul_maxlocals;
-       n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
-
-       inline_post_process(n_jd);
-
-       inline_interface_variables(iln);
-
-       /* for debugging, verify the inlined result */
-
-#if defined(INLINE_VERIFY_RESULT)
-       if (debug_verify_inlined_code) {
-               debug_verify_inlined_code = 0;
-               DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
-               if (!typecheck(n_jd)) {
-                       exceptions_clear_exception();
-                       DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
-                       return false;
-               }
-               else {
-                       DOLOG( printf("VERIFICATION PASSED.\n") );
-               }
-               debug_verify_inlined_code = 1;
-       }
-#endif /* defined(INLINE_VERIFY_RESULT) */
-
-       /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
-
-       n_jd->rd->freemem = DMNEW(s4, iln->ctx->maxinoutdepth + 1000) /* XXX max vars/block */;
-
-#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
-       if (   (n_jd->instructioncount >= opt_InlineMinSize)
-               && (n_jd->instructioncount <= opt_InlineMaxSize))
-       {
-          if (debug_counter < opt_InlineCount)
-#endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */
-          {
-                       /* install the inlined result */
-
-                       *jd->code = *n_jd->code;
-                       n_jd->code = jd->code;
-                       *jd = *n_jd;
-
-                       /* statistics and logging */
-
-#if !defined(NDEBUG)
-                       inline_stat_roots++;
-
-                       DOLOG_SHORT(
-                       printf("==== %d.INLINE ==================================================================\n",
-                               debug_counter);
-                       printf("\ninline tree:\n");
-                       dump_inline_tree(iln, 0);
-                       n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
-                       /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
-                       printf("-------- DONE -----------------------------------------------------------\n");
-                       fflush(stdout);
-                       );
-#endif
-          }
-
-#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
-               debug_counter++;
-       }
-#endif
-       return true;
-}
-
-
-/******************************************************************************/
-/* FIRST PASS: build inlining tree                                            */
-/******************************************************************************/
-
-
-/* inline_pre_parse_heuristics *************************************************
-
-   Perform heuristic checks whether a call site should be inlined.
-   These checks are evaluated before the callee has been parsed and analysed.
-
-   IN:
-       caller...........inlining node of the caller
-          callee...........the called method
-          site.............information on the call site
-
-   RETURN VALUE:
-       true........consider for inlining
-          false.......don't inline
-
-*******************************************************************************/
-
-static bool inline_pre_parse_heuristics(const inline_node *caller,
-                                                                               const methodinfo *callee,
-                                                                               inline_site *site)
-{
-#if defined(INLINE_MAX_DEPTH)
-       if (caller->depth >= INLINE_MAX_DEPTH)
-               return false;
-#endif
-
-       return true;
-}
-
-
-/* inline_post_parse_heuristics ************************************************
-
-   Perform heuristic checks whether a call site should be inlined.
-   These checks are evaluated after the callee has been parsed and analysed.
-
-   IN:
-       caller...........inlining node of the caller (const)
-          callee...........the called method (const)
-
-   RETURN VALUE:
-          true........consider for inlining
-          false.......don't inline
-
-*******************************************************************************/
-
-static bool inline_post_parse_heuristics(const inline_node *caller,
-                                                                                const inline_node *callee)
-{
-       return true;
-}
-
-
-/* inline_afterwards_heuristics ************************************************
-
-   Perform heuristic checks whether a call site should be inlined.
-   These checks are evaluated after the inlining plan for the callee has
-   been made.
-
-   IN:
-       caller...........inlining node of the caller (const)
-          callee...........the called method (const)
-
-   RETURN VALUE:
-          true........consider for inlining
-          false.......don't inline
-
-*******************************************************************************/
-
-static bool inline_afterwards_heuristics(const inline_node *caller,
-                                                                                const inline_node *callee)
-{
-       inline_node *cumulator;
-
-#if defined(INLINE_DEPTH_FIRST)
-       cumulator = caller;
-#else
-       cumulator = caller->ctx->master;
-#endif
-
-       if (0
-#if defined(INLINE_MAX_BLOCK_EXPANSION)
-               || (cumulator->cumul_basicblockcount + callee->cumul_basicblockcount
-                       > INLINE_MAX_BLOCK_EXPANSION*caller->ctx->master->jd->basicblockcount)
-#endif
-#if defined(INLINE_MAX_ICMD_EXPANSION)
-               || (cumulator->cumul_instructioncount + callee->cumul_instructioncount
-                       > INLINE_MAX_ICMD_EXPANSION*caller->ctx->master->jd->instructioncount)
-#endif
-          )
-       {
-               return false;
-       }
-
-       return true;
-}
-
-
-/* inline_is_monomorphic *******************************************************
-
-   Check if the given call site can be proven to be monomorphic.
-
-   IN:
-          callee...........the called method
-          call.............the invocation instruction
-
-   OUT:
-       site->speculative.....flags whether the inlining is speculative
-                                (only defined if return value is true)
-
-   RETURN VALUE:
-       true if the call site is (currently) monomorphic,
-          false if not or unknown
-
-*******************************************************************************/
-
-static bool inline_is_monomorphic(const methodinfo *callee,
-                                                                 const instruction *call,
-                                                                 inline_site *site)
-{
-       if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
-                               || call->opc == ICMD_INVOKESPECIAL))
-       {
-               site->speculative = false;
-               return true;
-       }
-
-       /* XXX search single implementation for abstract monomorphics */
-
-       if ((callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED
-                                       | ACC_ABSTRACT))
-                       == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED))
-       {
-               if (1) {
-                       DOLOG( printf("SPECULATIVE INLINE: "); method_println((methodinfo*)callee); );
-                       site->speculative = true;
-
-                       return true;
-               }
-       }
-
-       /* possibly polymorphic call site */
-
-       return false;
-}
-
-
-/* inline_can_inline ***********************************************************
-
-   Check if inlining of the given call site is possible.
-
-   IN:
-       caller...........inlining node of the caller
-          callee...........the called method
-          call.............the invocation instruction
-
-   OUT:
-       site->speculative.....flags whether the inlining is speculative
-                                (only defined if return value is true)
-
-   RETURN VALUE:
-       true if inlining is possible, false if not
-
-*******************************************************************************/
-
-static bool inline_can_inline(const inline_node *caller,
-                                                         const methodinfo *callee,
-                                                         const instruction *call,
-                                                         inline_site *site)
-{
-       const inline_node *active;
-
-       /* cannot inline native methods */
-
-       if (callee->flags & ACC_NATIVE)
-               return false;
-
-       /* cannot inline possibly polymorphic calls */
-
-       if (!inline_is_monomorphic(callee, call, site))
-               return false;
-
-       /* cannot inline recursive calls */
-
-       for (active = caller; active; active = active->parent) {
-               if (callee == active->m) {
-                       DOLOG( printf("RECURSIVE!\n") );
-                       return false;
-               }
-       }
-
-       /* inlining is possible */
-
-       return true;
-}
-
-
-/* inline_create_callee_node ***************************************************
-
-   Create an inlining node for the given callee.
-
-   IN:
-          caller...........inlining node of the caller (const)
-          callee...........the called method
-
-   RETURN VALUE:
-       the new inlining node
-
-*******************************************************************************/
-
-static inline_node * inline_create_callee_node(const inline_node *caller,
-                                                                                          methodinfo *callee)
-{
-       inline_node *cn;              /* the callee inline_node */
-
-       cn = DNEW(inline_node);
-       MZERO(cn, inline_node, 1);
-
-       cn->depth = caller->depth + 1;
-       cn->ctx = caller->ctx;
-       cn->m = callee;
-       cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
-       cn->isstatic = (callee->flags & ACC_STATIC);
-
-       return cn;
-}
-
-
-/* inline_set_callee_properties ************************************************
-
-   Set properties of the inlined call site.
-
-   IN:
-       caller...........inlining node of the caller (const)
-          cn...............the called method
-          site.............info about the call site (const)
-
-   OUT:
-       *cn..............has the properties set
-
-*******************************************************************************/
-
-static void inline_set_callee_properties(const inline_node *caller,
-                                                                                inline_node *cn,
-                                                                                const inline_site *site)
-{
-       s4           argi;
-       s4           i, j;
-       basicblock  *bptr;
-
-       /* set info about the call site */
-
-       cn->callerblock = site->bptr;
-       cn->callerins = site->iptr;
-       cn->callerpc = site->pc;
-       cn->o_handlers = site->handlers;
-       cn->n_handlercount = caller->n_handlercount + site->nhandlers;
-
-       /* determine if we need basic block boundaries before/after */
-
-       cn->blockbefore = false;
-       cn->blockafter = false;
-
-       if (cn->jd->branchtoentry)
-               cn->blockbefore = true;
-
-       if (cn->jd->branchtoend)
-               cn->blockafter = true;
-
-       if (cn->jd->returncount > 1)
-               cn->blockafter = true;
-
-       /* XXX make safer and reusable (maybe store last real block) */
-       for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
-               ;
-
-       if (cn->jd->returnblock != bptr)
-               cn->blockafter = true;
-
-       /* info about the callee */
-
-       cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
-       cn->prolog_instructioncount = cn->m->parseddesc->paramcount + 2;
-       cn->epilog_instructioncount = 1; /* INLINE_END */
-       cn->extra_instructioncount = 0;
-
-       /* we need a CHECKNULL for instance methods, except for <init> */
-
-       if (!cn->isstatic && cn->m->name != utf_init)
-               cn->prolog_instructioncount += 1;
-
-       /* deal with synchronized callees */
-
-       if (cn->synchronize) {
-               methoddesc         *md;
-               builtintable_entry *bte;
-
-               /* we need basic block boundaries because of the handler */
-
-               cn->blockbefore = true;
-               cn->blockafter = true;
-
-               /* for synchronized static methods                 */
-               /* we need an ACONST, MONITORENTER in the prolog   */
-               /* and ACONST, MONITOREXIT in the epilog           */
-
-               /* for synchronized instance methods               */
-               /* we need an COPY, MONITORENTER in the prolog     */
-               /* and MONITOREXIT in the epilog                   */
-
-               if (cn->isstatic) {
-                       cn->prolog_instructioncount += 2;
-                       cn->epilog_instructioncount += 2;
-               }
-               else {
-                       cn->prolog_instructioncount += 2;
-                       cn->epilog_instructioncount += 1;
-                       cn->localsoffset += 1;
-               }
-
-               /* and exception handler */
-               /* ALOAD, builtin_monitorexit, ATHROW */
-
-               cn->extra_instructioncount += 3;
-
-               /* exception table entries */
-
-               cn->extra_exceptiontablelength = 1 + cn->n_handlercount;
-
-               /* add exception handler block */
-
-               cn->cumul_basicblockcount_root++;
-
-               /* we must call the builtins */
-
-               bte = builtintable_get_internal(LOCK_monitor_enter);
-               md = bte->md;
-               if (md->memuse > cn->regdata->memuse)
-                       cn->regdata->memuse = md->memuse;
-               if (md->argintreguse > cn->regdata->argintreguse)
-                       cn->regdata->argintreguse = md->argintreguse;
-
-               bte = builtintable_get_internal(LOCK_monitor_exit);
-               md = bte->md;
-               if (md->memuse > cn->regdata->memuse)
-                       cn->regdata->memuse = md->memuse;
-               if (md->argintreguse > cn->regdata->argintreguse)
-                       cn->regdata->argintreguse = md->argintreguse;
-       }
-
-       /* determine pass-through variables */
-
-       i = site->iptr->s1.argcount - cn->m->parseddesc->paramcount; /* max # of pass-though vars */
-
-       cn->n_passthroughvars = DMNEW(s4, i);
-       j = 0;
-       for (argi = site->iptr->s1.argcount - 1; argi >= cn->m->parseddesc->paramcount; --argi) {
-               s4 idx = site->iptr->sx.s23.s2.args[argi];
-               if (idx >= caller->jd->localcount) {
-                       cn->n_passthroughvars[j] = idx;
-                       j++;
-               }
-               else {
-                       DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
-               }
-       }
-       assert(j <= i);
-       cn->n_selfpassthroughcount = j;
-       cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
-}
-
-
-/* inline_cumulate_counters ****************************************************
-
-   Cumulate counters after a node has been decided to become inlined.
-
-   IN:
-       caller...........inlining node of the caller
-          callee...........inlining node of the callee (const)
-
-   OUT:
-       *caller..........gets cumulated values added
-
-*******************************************************************************/
-
-static void inline_cumulate_counters(inline_node *caller,
-                                                                        const inline_node *cn)
-{
-       caller->cumul_instructioncount += cn->prolog_instructioncount;
-       caller->cumul_instructioncount += cn->epilog_instructioncount;
-       caller->cumul_instructioncount += cn->extra_instructioncount;
-       caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
-
-       caller->cumul_basicblockcount += cn->cumul_basicblockcount;
-       caller->cumul_basicblockcount_root += cn->cumul_basicblockcount_root;
-       caller->cumul_blockmapcount += cn->cumul_blockmapcount;
-       caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
-       caller->cumul_exceptiontablelength += cn->extra_exceptiontablelength;
-
-       if (cn->cumul_maxlocals > caller->cumul_maxlocals)
-               caller->cumul_maxlocals = cn->cumul_maxlocals;
-
-       /* XXX extra block after inlined call */
-       if (cn->blockafter) {
-               caller->cumul_basicblockcount += 1;
-               caller->cumul_blockmapcount += 1;
-       }
-}
-
-
-/* inline_analyse_callee *******************************************************
-
-   Analyse an inlining candidate callee.
-
-   IN:
-       caller...........inlining node of the caller
-          callee...........the called method
-          site.............info about the call site
-
-   OUT:
-       site->inlined....true if the callee has been selected for inlining
-
-   RETURN VALUE:
-       the inline node of the callee, or
-       NULL if an error has occurred (don't use the inlining plan in this case)
-
-*******************************************************************************/
-
-static inline_node * inline_analyse_callee(inline_node *caller,
-                                                                                  methodinfo *callee,
-                                                                                  inline_site *site)
-{
-       inline_node *cn;              /* the callee inline_node */
-
-       /* create an inline tree node */
-
-       cn = inline_create_callee_node(caller, callee);
-
-       /* get the intermediate representation of the callee */
-
-       if (!inline_jit_compile(cn))
-               return NULL;
-
-       /* evaluate heuristics after parsing the callee */
-
-       if (!inline_post_parse_heuristics(caller, cn))
-               return cn;
-
-       /* the call site will be inlined */
-
-       site->inlined = true;
-
-       /* set info about the call site */
-
-       inline_set_callee_properties(caller, cn, site);
-
-       /* insert the node into the inline tree */
-
-       inline_insert_inline_node(caller, cn);
-
-       /* analyse recursively */
-
-       if (!inline_analyse_code(cn))
-               return NULL;
-
-       if (!inline_afterwards_heuristics(caller, cn)) {
-#if defined(INLINE_CANCEL_ON_THRESHOLD)
-               return NULL;
-#else
-               inline_remove_inline_node(caller, cn);
-               caller->ctx->stopped = true;
-               site->inlined = false;
-               return cn;
-#endif
-       }
-
-       /* cumulate counters */
-
-#if defined(INLINE_DEPTH_FIRST)
-       inline_cumulate_counters(caller, cn);
-#endif
-
-#if defined(INLINE_BREADTH_FIRST)
-       while (caller) {
-               inline_cumulate_counters(caller, cn);
-               caller = caller->parent;
-       }
-#endif
-
-       return cn;
-}
-
-
-/* inline_process_candidate ****************************************************
-
-   Process a selected inlining candidate.
-
-   IN:
-       cand.............the candidate
-
-   RETURN VALUE:
-       true........everything ok
-          false.......an error has occurred, don't use the plan
-
-*******************************************************************************/
-
-static bool inline_process_candidate(inline_candidate *cand)
-{
-       inline_node *cn;
-
-       cn = inline_analyse_callee(cand->caller,
-                                                          cand->callee,
-                                                          &(cand->site));
-
-       if (!cn)
-               return false;
-
-       if (!cand->site.inlined)
-               return true;
-
-       /* store assumptions */
-
-       if (cand->site.speculative)
-               method_add_assumption_monomorphic(cand->callee, cand->caller->ctx->master->m);
-
-       return true;
-}
-
-
-/* inline_analyse_code *********************************************************
-
-   Analyse the intermediate code of the given inlining node.
-
-   IN:
-       iln..............the inlining node
-
-   OUT:
-       *iln.............the inlining plan
-
-   RETURN VALUE:
-       true........everything ok
-          false.......an error has occurred, don't use the plan
-
-*******************************************************************************/
-
-static bool inline_analyse_code(inline_node *iln)
-{
-       methodinfo *m;
-       basicblock *bptr;
-       s4 len;
-       instruction *iptr;
-       methodinfo *callee;
-       exception_entry **handlers;
-       exception_entry *ex;
-       s4 nhandlers;
-       s4 blockendpc;
-       jitdata *mjd;
-       inline_site site;
-
-       assert(iln);
-
-       m = iln->m;
-       mjd = iln->jd;
-
-       /* initialize cumulative counters */
-
-       iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
-       iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
-
-       /* iterate over basic blocks */
-
-       blockendpc = 0;
-
-       for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
-
-               /* count the block */
-               /* ignore dummy end blocks (but count them for the blockmap) */
-
-               iln->cumul_blockmapcount++;
-               if ((bptr != mjd->basicblocks || iln->blockbefore)
-                               &&
-                       (bptr->icount > 0 || bptr->next != NULL))
-                       iln->cumul_basicblockcount++;
-
-               /* skip dead code */
-
-               if (bptr->flags < BBREACHED)
-                       continue;
-
-               /* allocate the buffer of active exception handlers */
-               /* XXX this wastes some memory, but probably it does not matter */
-
-               handlers = DMNEW(exception_entry*, mjd->exceptiontablelength + 1);
-
-               /* determine the active exception handlers for this block     */
-               /* XXX maybe the handlers of a block should be part of our IR */
-               /* XXX this should share code with the type checkers          */
-               nhandlers = 0;
-               for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
-                       if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
-                               handlers[nhandlers++] = ex;
-                       }
-               }
-               handlers[nhandlers] = NULL;
-
-               len = bptr->icount;
-               iptr = bptr->iinstr;
-
-               blockendpc += len;
-               iln->cumul_instructioncount += len;
-
-               /* iterate over the instructions of the block */
-
-               for (; --len >= 0; ++iptr) {
-
-                       switch (iptr->opc) {
-                               case ICMD_INVOKEVIRTUAL:
-                               case ICMD_INVOKESPECIAL:
-                               case ICMD_INVOKESTATIC:
-                               case ICMD_INVOKEINTERFACE:
-
-                                       if (!INSTRUCTION_IS_UNRESOLVED(iptr) && !iln->ctx->stopped) {
-                                               callee = iptr->sx.s23.s3.fmiref->p.method;
-
-                                               if (inline_can_inline(iln, callee, iptr, &site)) {
-                                                       site.inlined = false;
-                                                       site.bptr = bptr;
-                                                       site.iptr = iptr;
-                                                       site.pc = blockendpc - len - 1;
-                                                       site.handlers = handlers;
-                                                       site.nhandlers = nhandlers;
-
-                                                       if (inline_pre_parse_heuristics(iln, callee, &site)) {
-#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
-                                                               inline_add_candidate(iln->ctx, iln, callee, &site);
-#else
-                                                               inline_candidate cand;
-                                                               cand.caller = iln;
-                                                               cand.callee = callee;
-                                                               cand.site   = site;
-
-                                                               if (!inline_process_candidate(&cand))
-                                                                       return false;
-#endif
-                                                       }
-                                               }
-                                       }
-                                       break;
-
-                               case ICMD_RETURN:
-                               case ICMD_IRETURN:
-                               case ICMD_ARETURN:
-                               case ICMD_LRETURN:
-                               case ICMD_FRETURN:
-                               case ICMD_DRETURN:
-                                       /* extra ICMD_MOVE may be necessary */
-                                       iln->cumul_instructioncount++;
-                                       break;
-                       }
-               }
-
-               /* end of basic block */
-       }
-
-       return true;
-}
-
-
-static void inline_cumulate_counters_recursive(inline_node *iln)
-{
-       inline_node *child;
-
-       child = iln->children;
-       if (child) {
-               do {
-                       inline_cumulate_counters_recursive(child);
-                       inline_cumulate_counters(iln, child);
-                       child = child->next;
-               } while (child != iln->children);
-       }
-}
-
-
-/* inline_make_inlining_plan ***************************************************
-
-   Make an inlining plan for the given root node
-
-   IN:
-       iln..............the root node
-
-   OUT:
-       *iln.............the inlining plan
-
-   RETURN VALUE:
-       true........everything ok
-          false.......an error has occurred, don't use the plan
-
-*******************************************************************************/
-
-#if defined(INLINE_KNAPSACK)
-static bool inline_make_inlining_plan(inline_node *iln)
-{
-       inline_candidate *cand;
-#if defined(INLINE_COST_BUDGET)
-       s4 budget = INLINE_COST_BUDGET;
-#   define BUDGETMEMBER cost
-#endif
-#if defined(INLINE_WEIGHT_BUDGET)
-       double budget = INLINE_WEIGHT_BUDGET;
-#   define BUDGETMEMBER weight
-#endif
-
-       inline_analyse_code(iln);
-
-       DOLOG( printf("candidates in "); method_println(iln->m);
-                  inline_candidates_println(iln->ctx); );
-
-       while ((cand = inline_pick_best_candidate(iln->ctx)) != NULL)
-       {
-               if (cand->BUDGETMEMBER <= budget) {
-                       DOLOG( printf("    picking: "); inline_candidate_println(cand); );
-
-                       if (!inline_process_candidate(cand))
-                               return false;
-
-#if !defined(INLINE_ADD_NEGATIVE_TO_BUDGET)
-                       if (cand->BUDGETMEMBER > 0)
-#endif
-                               budget -= cand->BUDGETMEMBER;
-               }
-       }
-
-       inline_cumulate_counters_recursive(iln);
-
-       return true;
-}
-#endif /* defined(INLINE_KNAPSACK) */
-
-
-#if defined(INLINE_DEPTH_FIRST)
-static bool inline_make_inlining_plan(inline_node *iln)
-{
-       return inline_analyse_code(iln);
-}
-#endif /* defined(INLINE_DEPTH_FIRST) */
-
-
-#if defined(INLINE_BREADTH_FIRST)
-static bool inline_make_inlining_plan(inline_node *iln)
-{
-       inline_candidate *cand;
-
-       inline_analyse_code(iln);
-
-       DOLOG( printf("candidates in "); method_println(iln->m);
-                  inline_candidates_println(iln->ctx); );
-
-       while (!iln->ctx->stopped
-                  && (cand = inline_pick_best_candidate(iln->ctx)) != NULL)
-       {
-               DOLOG( printf("    picking: "); inline_candidate_println(cand); );
-
-               if (!inline_process_candidate(cand))
-                       return false;
-       }
-
-       return true;
-}
-#endif /* defined(INLINE_BREADTH_FIRST) */
-
-
-/* statistics *****************************************************************/
-
-#if defined(INLINE_STATISTICS)
-static void inline_gather_statistics_recursive(inline_node *iln)
-{
-       inline_node *child;
-
-       inline_stat_inlined_nodes++;
-
-       if (iln->depth > inline_stat_max_depth)
-               inline_stat_max_depth++;
-
-       child = iln->children;
-       if (child) {
-               do {
-                       inline_gather_statistics_recursive(child);
-                       child = child->next;
-               } while (child != iln->children);
-       }
-}
-#endif /* defined(INLINE_STATISTICS) */
-
-
-#if defined(INLINE_STATISTICS)
-static void inline_gather_statistics(inline_node *iln)
-{
-       inline_stat_roots_transformed++;
-
-       inline_gather_statistics_recursive(iln);
-}
-#endif /* defined(INLINE_STATISTICS) */
-
-
-/* post processing ************************************************************/
-
-#define POSTPROCESS_SRC(varindex)  live[varindex]--
-#define POSTPROCESS_DST(varindex)  live[varindex]++
-
-#define POSTPROCESS_SRCOP(s)  POSTPROCESS_SRC(iptr->s.varindex)
-#define POSTPROCESS_DSTOP(d)  POSTPROCESS_DST(iptr->d.varindex)
-
-#define MARKSAVED(varindex)  jd->var[varindex].flags |= SAVEDVAR
-
-#define MARK_ALL_SAVED                                               \
-    do {                                                             \
-        for (i=0; i<jd->vartop; ++i)                                 \
-            if (live[i])                                             \
-                MARKSAVED(i);                                        \
-    } while (0)
-
-static void inline_post_process(jitdata *jd)
-{
-       codeinfo   *code;
-       basicblock *bptr;
-       instruction *iptr;
-       instruction *iend;
-       s4 i;
-       icmdtable_entry_t *icmdt;
-       s4 *live;
-       methoddesc *md;
-       builtintable_entry *bte;
-
-       /* Get required compiler data. */
-
-       code = jd->code;
-
-       /* reset the SAVEDVAR flag of all variables */
-
-       for (i=0; i<jd->vartop; ++i)
-               jd->var[i].flags &= ~SAVEDVAR;
-
-       /* allocate the life counters */
-
-       live = DMNEW(s4, jd->vartop);
-       MZERO(live, s4, jd->vartop);
-
-       /* iterate over all basic blocks */
-
-       for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
-               if (bptr->flags < BBREACHED)
-                       continue;
-
-               /* make invars live */
-
-               for (i=0; i<bptr->indepth; ++i)
-                       POSTPROCESS_DST(bptr->invars[i]);
-
-               iptr = bptr->iinstr;
-               iend = iptr + bptr->icount;
-
-               for (; iptr < iend; ++iptr) {
-
-                       icmdt = &(icmd_table[iptr->opc]);
-
-                       switch (icmdt->dataflow) {
-                               case DF_3_TO_0:
-                                       POSTPROCESS_SRCOP(sx.s23.s3);
-                               case DF_2_TO_0:
-                                       POSTPROCESS_SRCOP(sx.s23.s2);
-                               case DF_1_TO_0:
-                                       POSTPROCESS_SRCOP(s1);
-                               case DF_0_TO_0:
-                                       if (icmdt->flags & ICMDTABLE_CALLS) {
-                                               code_unflag_leafmethod(code);
-                                               MARK_ALL_SAVED;
-                                       }
-                                       break;
-
-                               case DF_2_TO_1:
-                                       POSTPROCESS_SRCOP(sx.s23.s2);
-                               case DF_1_TO_1:
-                               case DF_MOVE:
-                                       POSTPROCESS_SRCOP(s1);
-                               case DF_0_TO_1:
-                                       if (icmdt->flags & ICMDTABLE_CALLS) {
-                                               code_unflag_leafmethod(code);
-                                               MARK_ALL_SAVED;
-                                       }
-                               case DF_COPY:
-                                       POSTPROCESS_DSTOP(dst);
-                                       break;
-
-                               case DF_N_TO_1:
-                                       for (i=0; i<iptr->s1.argcount; ++i) {
-                                               POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
-                                       }
-                                       if (icmdt->flags & ICMDTABLE_CALLS) {
-                                               code_unflag_leafmethod(code);
-                                               MARK_ALL_SAVED;
-                                       }
-                                       POSTPROCESS_DSTOP(dst);
-                                       break;
-
-                               case DF_INVOKE:
-                                       INSTRUCTION_GET_METHODDESC(iptr, md);
-               post_process_call:
-                                       code_unflag_leafmethod(code);
-                                       for (i=0; i<md->paramcount; ++i) {
-                                               POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
-                                       }
-                                       for (; i<iptr->s1.argcount; ++i) {
-                                               MARKSAVED(iptr->sx.s23.s2.args[i]);
-                                       }
-                                       if (md->returntype.type != TYPE_VOID)
-                                               POSTPROCESS_DSTOP(dst);
-                                       break;
-
-                               case DF_BUILTIN:
-                                       bte = iptr->sx.s23.s3.bte;
-                                       md = bte->md;
-                                       goto post_process_call;
-
-                               default:
-                                       assert(0);
-                       }
-
-               } /* end instruction loop */
-
-               /* consume outvars */
-
-               for (i=0; i<bptr->outdepth; ++i)
-                       POSTPROCESS_SRC(bptr->outvars[i]);
-
-#if !defined(NDEBUG)
-               for (i=jd->localcount; i < jd->vartop; ++i)
-                       assert(live[i] == 0);
-#endif
-
-       } /* end basic block loop */
-}
-
-
-/* inline_create_root_node *****************************************************
-
-   Create the root node of the inlining tree.
-
-   IN:
-          jd...............the current jitdata of the root method
-
-   RETURN VALUE:
-       the root node of the inlining tree
-
-*******************************************************************************/
-
-static inline_node * inline_create_root_node(jitdata *jd)
-{
-       inline_node *iln;
-
-       iln = DNEW(inline_node);
-       MZERO(iln, inline_node, 1);
-
-       iln->m = jd->m;
-       iln->jd = jd;
-       iln->regdata = jd->rd;
-
-       iln->blockbefore = true;
-       iln->blockafter = true;
-
-       iln->cumul_instructioncount = 0;
-       iln->cumul_basicblockcount = 1 /* dummy end block */;
-
-       /* create inlining context */
-
-       iln->ctx = DNEW(inline_context);
-       MZERO(iln->ctx, inline_context, 1);
-       iln->ctx->master = iln;
-       iln->ctx->next_debugnr = 1; /* XXX debug */
-
-       return iln;
-}
-
-
-/******************************************************************************/
-/* MAIN DRIVER FUNCTION                                                       */
-/******************************************************************************/
-
-bool inline_inline(jitdata *jd)
-{
-       inline_node *iln;
-
-       DOLOG( printf("==== INLINE ==================================================================\n");
-                  show_method(jd, SHOW_STACK); );
-
-#if defined(INLINE_STATISTICS)
-       inline_stat_roots++;
-#endif
-
-       iln = inline_create_root_node(jd);
-
-       if (inline_make_inlining_plan(iln)) {
-
-               /* add blocks to the root node */
-
-               iln->cumul_basicblockcount += iln->cumul_basicblockcount_root;
-               iln->cumul_blockmapcount   += iln->cumul_basicblockcount_root;
-
-               DOLOG( printf("==== INLINE TRANSFORM ========================================================\n"); );
-
-               if (iln->children)
-                       inline_transform(iln, jd);
-
-#if defined(INLINE_STATISTICS)
-               inline_gather_statistics(iln);
-#endif
-       }
-
-       DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
-                  fflush(stdout); );
-
-       return true;
-}
-
-/*
- * 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/jit/inline/inline.cpp b/src/vm/jit/inline/inline.cpp
new file mode 100644 (file)
index 0000000..73c8667
--- /dev/null
@@ -0,0 +1,3244 @@
+/* src/vm/jit/inline/inline.c - method inlining
+
+   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 <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "threads/lock.hpp"
+#include "threads/mutex.hpp"
+#include "threads/thread.hpp"
+
+#include "toolbox/logging.h"
+
+#include "vm/jit/builtin.hpp"
+#include "vm/class.hpp"
+#include "vm/global.h"
+#include "vm/initialize.hpp"
+#include "vm/method.hpp"
+#include "vm/options.h"
+#include "vm/statistics.h"
+
+#include "vm/jit/jit.hpp"
+#include "vm/jit/parse.hpp"
+#include "vm/jit/reg.h"
+#include "vm/jit/show.hpp"
+#include "vm/jit/stack.h"
+
+#include "vm/jit/inline/inline.hpp"
+#include "vm/jit/loop/loop.h"
+
+#include "vm/jit/verify/typecheck.hpp"
+
+
+/* algorithm tuning constants *************************************************/
+
+/* Algorithm Selection                                                        */
+/* Define exactly one of the following three to select the inlining           */
+/* heuristics.                                                                */
+
+/*#define INLINE_DEPTH_FIRST*/
+/*#define INLINE_BREADTH_FIRST*/
+#define INLINE_KNAPSACK
+
+/* Parameters for knapsack heuristics:                                        */
+
+#if defined(INLINE_KNAPSACK)
+
+#define INLINE_COUNTDOWN_INIT       1000
+#define INLINE_COST_OFFSET          -16
+#define INLINE_COST_BUDGET          100
+/*#define INLINE_WEIGHT_BUDGET        5.0*/
+/*#define INLINE_ADD_NEGATIVE_TO_BUDGET*/
+/*#define INLINE_MAX_DEPTH            3*/
+/*#define INLINE_DIVIDE_COST_BY_FREQ */
+
+#endif
+
+/* Parameters for depth-first heuristics:                                     */
+
+#if defined(INLINE_DEPTH_FIRST)
+
+#define INLINE_MAX_DEPTH            3
+#define INLINE_MAX_BLOCK_EXPANSION  10
+/*#define INLINE_MAX_ICMD_EXPANSION  10*/
+/*#define INLINE_CANCEL_ON_THRESHOLD*/
+
+#endif
+
+/* Parameters for breadth-first heuristics:                                   */
+
+#if defined(INLINE_BREADTH_FIRST)
+
+/*#define INLINE_MAX_BLOCK_EXPANSION  10*/
+#define INLINE_MAX_ICMD_EXPANSION  5
+
+#endif
+
+
+/* debugging ******************************************************************/
+
+#if !defined(NDEBUG)
+#define INLINE_VERBOSE
+#define DOLOG(code)       do{ if (opt_TraceInlining >= 2) { code; } }while(0)
+#define DOLOG_SHORT(code) do{ if (opt_TraceInlining >= 1) { code; } }while(0)
+#else
+#define DOLOG(code)
+#endif
+
+#if defined(ENABLE_VERIFIER) && !defined(NDEBUG)
+/* Define this to verify the resulting code after inlining.                 */
+/* Note: This is only useful for development and may require patches to the */
+/*       verifier code.                                                     */
+/* #define INLINE_VERIFY_RESULT */
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* types **********************************************************************/
+
+typedef struct inline_node inline_node;
+typedef struct inline_target_ref inline_target_ref;
+typedef struct inline_context inline_context;
+typedef struct inline_block_map inline_block_map;
+typedef struct inline_site inline_site;
+typedef struct inline_candidate inline_candidate;
+
+struct inline_node {
+       inline_context *ctx;
+
+       jitdata *jd;
+       methodinfo *m;
+       inline_node *children;
+       inline_node *next;                             /* next node at this depth */
+       inline_node *prev;                             /* prev node at this depth */
+       int depth;                                  /* inlining depth, 0 for root */
+
+       /* info about the call site (if depth > 0)*/
+       inline_node *parent;                /* node of the caller (NULL for root) */
+       basicblock *callerblock;         /* original block containing the INVOKE* */
+       instruction *callerins;               /* the original INVOKE* instruction */
+       s4 callerpc;
+       s4 *n_passthroughvars;
+       int n_passthroughcount;
+       int n_selfpassthroughcount;  /* # of pass-through vars of the call itself */
+       exception_entry **o_handlers;
+       int n_handlercount;                 /* # of handlers protecting this call */
+       int n_resultlocal;
+       int synclocal;                    /* variable used for synchr., or UNUSED */
+       bool isstatic;                                   /* this is a static call */
+
+       bool blockbefore;                  /* block boundary before inlined body? */
+       bool blockafter;                   /* block boundary after inlined body?  */
+
+       /* info about the callee */
+       int localsoffset;
+       int prolog_instructioncount;         /* # of ICMDs in the inlining prolog */
+       int epilog_instructioncount;         /* # of ICMDs in the inlining epilog */
+       int extra_instructioncount;
+       int extra_exceptiontablelength;   /* # of extra handlers to put in caller */
+       bool synchronize;                /* do we have to synchronize enter/exit? */
+       basicblock *handler_monitorexit;     /* handler for synchronized inlinees */
+       s4 *varmap;
+
+       /* cumulative values */
+       int cumul_instructioncount;  /* ICMDs in this node and its children       */
+       int cumul_basicblockcount;   /* BBs started by this node and its children */
+       int cumul_basicblockcount_root;  /* BBs that have to be added to the root */
+                                        /* node if this node is inlined          */
+       int cumul_blockmapcount;
+       int cumul_maxlocals;
+       int cumul_exceptiontablelength;
+
+       /* output */
+       instruction *inlined_iinstr;
+       instruction *inlined_iinstr_cursor;
+       basicblock *inlined_basicblocks;
+       basicblock *inlined_basicblocks_cursor;
+
+       /* register data */
+       registerdata *regdata;
+
+       /* temporary */
+       inline_target_ref *refs;
+       instruction *inline_start_instruction;
+       s4 *javalocals;
+
+       /* XXX debug */
+       char *indent;
+       int debugnr;
+};
+
+struct inline_target_ref {
+       inline_target_ref *next;
+       union {
+               basicblock **block;
+               s4 *nr;
+       } ref;
+       basicblock *target;
+       bool isnumber;
+};
+
+struct inline_block_map {
+       inline_node *iln;
+       basicblock *o_block;
+       basicblock *n_block;
+};
+
+struct inline_context {
+       inline_node *master;
+
+       jitdata *resultjd;
+
+       inline_candidate *candidates;
+
+       int next_block_number;
+       inline_block_map *blockmap;
+       int blockmap_index;
+
+       int maxinoutdepth;
+
+       bool stopped;
+
+       int next_debugnr; /* XXX debug */
+};
+
+struct inline_site {
+       bool              speculative;  /* true, if inlining would be speculative */
+       bool              inlined;      /* true, if this site has been inlined    */
+
+       basicblock       *bptr;         /* basic block containing the call site   */
+       instruction      *iptr;         /* the invocation instruction             */
+       exception_entry **handlers;     /* active handlers at the call site       */
+       s4                nhandlers;    /* number of active handlers              */
+       s4                pc;           /* PC of the invocation instruction       */
+};
+
+struct inline_candidate {
+       inline_candidate *next;
+       int freq;
+       int cost;
+       double weight;
+       inline_node *caller;
+       methodinfo *callee;
+       inline_site site;
+};
+
+
+/* prototypes *****************************************************************/
+
+static bool inline_analyse_code(inline_node *iln);
+static void inline_post_process(jitdata *jd);
+
+
+/* debug helpers **************************************************************/
+
+#if !defined(NDEBUG)
+#include "inline_debug.inc"
+#endif
+
+
+/* statistics *****************************************************************/
+
+/*#define INLINE_STATISTICS*/
+
+#if !defined(NDEBUG)
+#define INLINE_STATISTICS
+#endif
+
+#if defined(INLINE_STATISTICS)
+int inline_stat_roots = 0;
+int inline_stat_roots_transformed = 0;
+int inline_stat_inlined_nodes = 0;
+int inline_stat_max_depth = 0;
+
+void inline_print_stats()
+{
+       printf("inlining statistics:\n");
+       printf("    roots analysed   : %d\n", inline_stat_roots);
+       printf("    roots transformed: %d\n", inline_stat_roots_transformed);
+       printf("    inlined nodes    : %d\n", inline_stat_inlined_nodes);
+       printf("    max depth        : %d\n", inline_stat_max_depth);
+}
+#endif
+
+
+/* compilation of callees *****************************************************/
+
+static bool inline_jit_compile_intern(jitdata *jd)
+{
+       methodinfo *m;
+
+       /* XXX should share code with jit.c */
+
+       assert(jd);
+
+       /* XXX initialize the static function's class */
+
+       m = jd->m;
+
+       /* call the compiler passes ***********************************************/
+
+       /* call parse pass */
+
+       DOLOG( log_message_class("Parsing ", m->clazz) );
+       if (!parse(jd)) {
+               return false;
+       }
+
+       /* call stack analysis pass */
+
+       if (!stack_analyse(jd)) {
+               return false;
+       }
+
+       return true;
+}
+
+
+static bool inline_jit_compile(inline_node *iln)
+{
+       bool                r;
+       methodinfo         *m;
+       jitdata            *jd;
+
+       /* XXX should share code with jit.c */
+
+       assert(iln);
+       m = iln->m;
+       assert(m);
+
+       /* enter a monitor on the method */
+
+       m->mutex->lock();
+
+       /* allocate jitdata structure and fill it */
+
+       jd = jit_jitdata_new(m);
+       iln->jd = jd;
+
+       jd->flags = 0; /* XXX */
+
+       /* initialize the register allocator */
+
+       reg_setup(jd);
+
+       /* setup the codegendata memory */
+
+       /* XXX do a pseudo setup */
+       jd->cd = (codegendata*) DumpMemory::allocate(sizeof(codegendata));
+       MZERO(jd->cd, codegendata, 1);
+       jd->cd->method = m;
+       /* XXX uses too much dump memory codegen_setup(jd); */
+
+       /* now call internal compile function */
+
+       r = inline_jit_compile_intern(jd);
+
+       if (r) {
+               iln->regdata = jd->rd;
+       }
+
+       /* free some memory */
+#if 0
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+       if (!opt_intrp)
+# endif
+               codegen_free(jd);
+#endif
+
+#endif
+
+       /* leave the monitor */
+
+       m->mutex->unlock();
+
+       return r;
+}
+
+
+/* inlining tree handling *****************************************************/
+
+static void inline_insert_inline_node(inline_node *parent, inline_node *child)
+{
+       inline_node *first;
+       inline_node *succ;
+
+       assert(parent && child);
+
+       child->parent = parent;
+
+       child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
+
+       first = parent->children;
+       if (!first) {
+               /* insert as only node */
+               parent->children = child;
+               child->next = child;
+               child->prev = child;
+               return;
+       }
+
+       /* {there is at least one child already there} */
+
+       /* XXX is this search necessary, or could we always add at the end? */
+
+       succ = first;
+       while (succ->callerpc < child->callerpc) {
+               succ = succ->next;
+               if (succ == first) {
+                       /* insert as last node */
+                       child->prev = first->prev;
+                       child->next = first;
+                       child->prev->next = child;
+                       child->next->prev = child;
+                       return;
+               }
+       }
+
+       assert(succ->callerpc > child->callerpc);
+
+       /* insert before succ */
+
+       child->prev = succ->prev;
+       child->next = succ;
+       child->prev->next = child;
+       child->next->prev = child;
+
+       if (parent->children == succ)
+               parent->children = child;
+}
+
+
+static void inline_remove_inline_node(inline_node *parent, inline_node *child)
+{
+       assert(parent);
+       assert(child);
+       assert(child->parent == parent);
+
+       if (child->prev == child) {
+               /* remove the only child node */
+               parent->children = NULL;
+       }
+       else {
+               child->prev->next = child->next;
+               child->next->prev = child->prev;
+
+               if (parent->children == child)
+                       parent->children = child->next;
+       }
+}
+
+
+/* inlining candidate handling ************************************************/
+
+#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
+static void inline_add_candidate(inline_context *ctx,
+                                                                inline_node *caller,
+                                                                methodinfo *callee,
+                                                                inline_site *site)
+{
+       inline_candidate **link;
+       inline_candidate *cand;
+
+       cand = (inline_candidate*) DumpMemory::allocate(sizeof(inline_candidate));
+#if defined(INLINE_DIVIDE_COST_BY_FREQ)
+       cand->freq = INLINE_COUNTDOWN_INIT - callee->hitcountdown;
+       if (cand->freq < 1)
+#endif
+               cand->freq = 1;
+#if defined(INLINE_KNAPSACK)
+       cand->cost = callee->jcodelength + INLINE_COST_OFFSET;
+#endif
+#if defined(INLINE_BREADTH_FIRST)
+       cand->cost = caller->depth;
+#endif
+       cand->caller = caller;
+       cand->callee = callee;
+       cand->site = *site;
+
+       cand->weight = (double)cand->cost / cand->freq;
+
+       for (link = &(ctx->candidates); ; link = &((*link)->next)) {
+               if (!*link || (*link)->weight > cand->weight) {
+                       cand->next = *link;
+                       *link = cand;
+                       break;
+               }
+       }
+}
+#endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
+
+#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
+static inline_candidate * inline_pick_best_candidate(inline_context *ctx)
+{
+       inline_candidate *cand;
+
+       cand = ctx->candidates;
+
+       if (cand)
+               ctx->candidates = cand->next;
+
+       return cand;
+}
+#endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
+
+#if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
+static void inline_candidate_println(inline_candidate *cand)
+{
+       printf("%10g (%5d / %5d) depth %2d ",
+                       cand->weight, cand->cost, cand->freq, cand->caller->depth + 1);
+       method_println(cand->callee);
+}
+#endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
+
+
+#if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
+static void inline_candidates_println(inline_context *ctx)
+{
+       inline_candidate *cand;
+
+       for (cand = ctx->candidates; cand != NULL; cand = cand->next) {
+               printf("    ");
+               inline_candidate_println(cand);
+       }
+}
+#endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
+
+
+/* variable handling **********************************************************/
+
+static s4 inline_new_variable(jitdata *jd, s4 type, s4 flags)
+{
+       s4 index;
+       s4 newcount;
+
+       index = jd->vartop++;
+       if (index >= jd->varcount) {
+               newcount = jd->vartop * 2; /* XXX */
+               jd->var = (varinfo*) DumpMemory::reallocate(jd->var, sizeof(varinfo) * jd->varcount, sizeof(varinfo) * newcount);
+               MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
+               jd->varcount = newcount;
+       }
+
+       jd->var[index].type = type;
+       jd->var[index].flags = flags;
+
+       return index;
+}
+
+
+static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
+{
+       varinfo *v;
+       s4       newidx;
+
+       v = &(origjd->var[origidx]);
+
+       newidx = inline_new_variable(jd, v->type, v->flags);
+
+       jd->var[newidx].vv = v->vv;
+
+       return newidx;
+}
+
+
+static s4 inline_new_temp_variable(jitdata *jd, s4 type)
+{
+       return inline_new_variable(jd, type, 0);
+}
+
+
+static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
+{
+       s4 idx;
+
+       idx = varmap[index];
+
+       if (idx < 0) {
+               idx = inline_new_variable_clone(jd, origjd, index);
+               varmap[index] = idx;
+       }
+
+       return idx;
+}
+
+
+static s4 *create_variable_map(inline_node *callee)
+{
+       s4 *varmap;
+       s4 i, t;
+       s4 varindex;
+       s4 n_javaindex;
+       s4 avail;
+       varinfo *v;
+
+       /* create the variable mapping */
+
+       varmap = (s4*) DumpMemory::allocate(sizeof(s4) * callee->jd->varcount);
+       for (i=0; i<callee->jd->varcount; ++i)
+               varmap[i] = -1;
+
+       /* translate local variables */
+
+       for (i=0; i<callee->m->maxlocals; ++i) {
+               for (t=0; t<5; ++t) {
+                       varindex = callee->jd->local_map[5*i + t];
+                       if (varindex == UNUSED)
+                               continue;
+
+                       v = &(callee->jd->var[varindex]);
+                       assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
+                       v->type = t; /* XXX restore if it is TYPE_VOID */
+
+                       avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
+
+                       if (avail == UNUSED) {
+                               avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, varindex);
+                               callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
+                       }
+
+                       varmap[varindex] = avail;
+               }
+       }
+
+       /* for synchronized instance methods we need an extra local */
+
+       if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
+               n_javaindex = callee->localsoffset - 1;
+               assert(n_javaindex >= 0);
+               assert(callee->parent);
+               assert(n_javaindex == callee->parent->localsoffset + callee->parent->m->maxlocals);
+
+               avail = callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR];
+
+               if (avail == UNUSED) {
+                       avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
+                       callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR] = avail;
+               }
+
+               callee->synclocal = avail;
+       }
+       else {
+               callee->synclocal = UNUSED;
+       }
+
+       return varmap;
+}
+
+
+/* basic block translation ****************************************************/
+
+#define INLINE_RETURN_REFERENCE(callee)  \
+       ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
+
+
+static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
+{
+       inline_target_ref *ref;
+
+       ref = (inline_target_ref*) DumpMemory::allocate(sizeof(inline_target_ref));
+       ref->ref.block = blockp;
+       ref->isnumber = false;
+       ref->next = iln->refs;
+       iln->refs = ref;
+}
+
+
+#if 0
+static void inline_add_blocknr_reference(inline_node *iln, s4 *nrp)
+{
+       inline_target_ref *ref;
+
+       ref = (inline_target_ref*) DumpMemory::allocate(inline_target_ref);
+       ref->ref.nr = nrp;
+       ref->isnumber = true;
+       ref->next = iln->refs;
+       iln->refs = ref;
+}
+#endif
+
+
+static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
+{
+       inline_context *ctx;
+
+       ctx = iln->ctx;
+       assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
+
+       ctx->blockmap[ctx->blockmap_index].iln = iln;
+       ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
+       ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
+
+       ctx->blockmap_index++;
+}
+
+
+static basicblock * inline_map_block(inline_node *iln,
+                                                                        basicblock *o_block,
+                                                                        inline_node *targetiln)
+{
+       inline_block_map *bm;
+       inline_block_map *bmend;
+
+       assert(iln);
+       assert(targetiln);
+
+       if (!o_block)
+               return NULL;
+
+       bm = iln->ctx->blockmap;
+       bmend = bm + iln->ctx->blockmap_index;
+
+       while (bm < bmend) {
+               assert(bm->iln && bm->o_block && bm->n_block);
+               if (bm->o_block == o_block && bm->iln == targetiln)
+                       return bm->n_block;
+               bm++;
+       }
+
+       assert(false);
+       return NULL; /* not reached */
+}
+
+
+static void inline_resolve_block_refs(inline_target_ref **refs,
+                                                                         basicblock *o_bptr,
+                                                                         basicblock *n_bptr,
+                                                                         bool returnref)
+{
+       inline_target_ref *ref;
+       inline_target_ref *prev;
+
+       prev = NULL;
+       for (ref = *refs; ref != NULL; ref = ref->next) {
+               if (ref->isnumber && !returnref) {
+                       if (*(ref->ref.nr) == JAVALOCAL_FROM_RETADDR(o_bptr->nr)) {
+                               *(ref->ref.nr) = JAVALOCAL_FROM_RETADDR(n_bptr->nr);
+                               goto remove_ref;
+                       }
+               }
+               else {
+                       if (*(ref->ref.block) == o_bptr) {
+                               *(ref->ref.block) = n_bptr;
+                               goto remove_ref;
+                       }
+               }
+
+               /* skip this ref */
+
+               prev = ref;
+               continue;
+
+remove_ref:
+               /* remove this ref */
+
+               if (prev) {
+                       prev->next = ref->next;
+               }
+               else {
+                       *refs = ref->next;
+               }
+       }
+}
+
+
+/* basic block creation *******************************************************/
+
+static basicblock * create_block(inline_node *container,
+                                                                inline_node *iln,
+                                                                inline_node *inner,
+                                                                int indepth)
+{
+       basicblock  *n_bptr;
+       inline_node *outer;
+       s4           i;
+       s4           depth;
+       s4           varidx;
+       s4           newvaridx;
+
+       assert(container);
+       assert(iln);
+       assert(inner);
+       assert(indepth >= 0);
+
+       n_bptr = container->inlined_basicblocks_cursor++;
+       assert(n_bptr);
+       assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
+
+       BASICBLOCK_INIT(n_bptr, iln->m);
+
+       n_bptr->iinstr = container->inlined_iinstr_cursor;
+       n_bptr->next = n_bptr + 1;
+       n_bptr->nr = container->ctx->next_block_number++;
+       n_bptr->indepth = indepth;
+       n_bptr->flags = BBFINISHED; /* XXX */
+
+       /* set the inlineinfo of the new block */
+
+       if (iln->inline_start_instruction)
+               n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
+
+       if (indepth > container->ctx->maxinoutdepth)
+               container->ctx->maxinoutdepth = indepth;
+
+       if (indepth) {
+               n_bptr->invars = (s4*) DumpMemory::allocate(sizeof(s4) * indepth);
+
+
+               for (i=0; i<indepth; ++i)
+                       n_bptr->invars[i] = -1; /* XXX debug */
+
+               /* pass-through variables enter the block */
+
+               outer = inner->parent;
+               while (outer != NULL) {
+                       depth = outer->n_passthroughcount;
+
+                       assert(depth + inner->n_selfpassthroughcount <= indepth);
+
+                       for (i=0; i<inner->n_selfpassthroughcount; ++i) {
+                               varidx = inner->n_passthroughvars[i];
+                               newvaridx =
+                                       inline_new_variable_clone(container->ctx->resultjd,
+                                                                                         outer->jd,
+                                                                                         varidx);
+                               n_bptr->invars[depth + i] = newvaridx;
+                               outer->varmap[varidx] = newvaridx;
+                       }
+                       inner = outer;
+                       outer = outer->parent;
+               }
+       }
+       else {
+               n_bptr->invars = NULL;
+       }
+
+       /* XXX for the verifier. should not be here */
+
+       {
+               varinfo *dv;
+
+               dv = (varinfo*) DumpMemory::allocate(sizeof(varinfo) * (iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS));
+               MZERO(dv, varinfo,  iln->ctx->resultjd->localcount + VERIFIER_EXTRA_LOCALS);
+               n_bptr->inlocals = dv;
+       }
+
+       return n_bptr;
+}
+
+
+static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
+{
+       s4 *jl;
+       s4 i, j;
+
+       jl = (s4*) DumpMemory::allocate(sizeof(s4) * iln->jd->maxlocals);
+
+       for (i=0; i<iln->jd->maxlocals; ++i) {
+               j = javalocals[i];
+               if (j > UNUSED)
+                       j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
+               jl[i] = j;
+
+#if 0
+               if (j < UNUSED) {
+                       /* an encoded returnAddress value - must be relocated */
+                       inline_add_blocknr_reference(iln, &(jl[i]));
+               }
+#endif
+       }
+
+       return jl;
+}
+
+
+static basicblock * create_body_block(inline_node *iln,
+                                                                         basicblock *o_bptr, s4 *varmap)
+{
+       basicblock *n_bptr;
+       s4 i;
+
+       n_bptr = create_block(iln, iln, iln,
+                                                 o_bptr->indepth + iln->n_passthroughcount);
+
+       n_bptr->type = o_bptr->type;
+       n_bptr->flags = o_bptr->flags;
+       n_bptr->bitflags = o_bptr->bitflags;
+
+       /* resolve references to this block */
+
+       inline_resolve_block_refs(&(iln->refs), o_bptr, n_bptr, false);
+
+       /* translate the invars of the original block */
+
+       for (i=0; i<o_bptr->indepth; ++i) {
+               n_bptr->invars[iln->n_passthroughcount + i] =
+                       inline_translate_variable(iln->ctx->resultjd, iln->jd,
+                               varmap,
+                               o_bptr->invars[i]);
+       }
+
+       /* translate javalocals info (not for dead code) */
+
+       if (n_bptr->flags >= BBREACHED)
+               n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
+
+       return n_bptr;
+}
+
+
+static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
+{
+       basicblock *n_bptr;
+       s4 retcount;
+       s4 idx;
+
+       /* number of return variables */
+
+       retcount = (callee->n_resultlocal == -1
+                               && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
+
+       /* start the epilog block */
+
+       n_bptr = create_block(caller, caller, callee,
+                                                 callee->n_passthroughcount + retcount);
+
+       /* resolve references to the return block */
+
+       inline_resolve_block_refs(&(callee->refs),
+                                                         INLINE_RETURN_REFERENCE(callee),
+                                                         n_bptr,
+                                                         true);
+
+       /* return variable */
+
+       if (retcount) {
+               idx = inline_new_variable(caller->ctx->resultjd,
+                          callee->m->parseddesc->returntype.type, 0 /* XXX */);
+               n_bptr->invars[callee->n_passthroughcount] = idx;
+               varmap[callee->callerins->dst.varindex] = idx;
+       }
+
+       /* set javalocals */
+
+       n_bptr->javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * caller->jd->maxlocals);
+       MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
+
+       /* set block flags & type */
+
+       n_bptr->flags = /* XXX original block flags */ BBFINISHED;
+       n_bptr->type = BBTYPE_STD;
+
+       return n_bptr;
+}
+
+
+static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
+{
+       inline_node *outer;
+       s4           i;
+       s4           depth;
+       s4           varidx;
+
+       n_bptr->outdepth = outdepth;
+       n_bptr->outvars = (s4*) DumpMemory::allocate(sizeof(s4) * outdepth);
+
+       for (i=0; i<outdepth; ++i)
+               n_bptr->outvars[i] = 0; /* XXX debug */
+
+       if (outdepth > iln->ctx->maxinoutdepth)
+               iln->ctx->maxinoutdepth = outdepth;
+
+       /* pass-through variables leave the block */
+
+       outer = inner->parent;
+       while (outer != NULL) {
+               depth = outer->n_passthroughcount;
+
+               assert(depth + inner->n_selfpassthroughcount <= outdepth);
+
+               for (i=0; i<inner->n_selfpassthroughcount; ++i) {
+                       varidx = inner->n_passthroughvars[i];
+                       n_bptr->outvars[depth + i] =
+                               inline_translate_variable(iln->ctx->resultjd,
+                                                                                 outer->jd,
+                                                                                 outer->varmap,
+                                                                                 varidx);
+               }
+               inner = outer;
+               outer = outer->parent;
+       }
+}
+
+
+static void close_prolog_block(inline_node *iln,
+                                                          basicblock *n_bptr,
+                                                          inline_node *nextcall)
+{
+       /* XXX add original outvars! */
+       close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
+
+       /* pass-through variables */
+
+       DOLOG( printf("closed prolog block:\n");
+                  show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
+}
+
+
+static void close_body_block(inline_node *iln,
+                                                        basicblock *n_bptr,
+                                                        basicblock *o_bptr,
+                                                        s4 *varmap,
+                                                        s4 retcount,
+                                                        s4 retidx)
+{
+       s4 i;
+
+       close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
+
+       /* translate the outvars of the original block */
+
+       /* XXX reuse code */
+       for (i=0; i<o_bptr->outdepth; ++i) {
+               n_bptr->outvars[iln->n_passthroughcount + i] =
+                       inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
+                                       o_bptr->outvars[i]);
+       }
+
+       /* set the return variable, if any */
+
+       if (retcount) {
+               assert(retidx >= 0);
+               n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
+       }
+}
+
+
+/* inlined code generation ****************************************************/
+
+static instruction * inline_instruction(inline_node *iln,
+                                                                               s4 opcode,
+                                                                               instruction *o_iptr)
+{
+       instruction *n_iptr;
+
+       n_iptr = (iln->inlined_iinstr_cursor++);
+       assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+
+       n_iptr->opc = opcode;
+       n_iptr->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
+       n_iptr->line = o_iptr->line;
+
+       return n_iptr;
+}
+
+static void inline_generate_sync_builtin(inline_node *iln,
+                                                                                inline_node *callee,
+                                                                                instruction *o_iptr,
+                                                                                s4 instancevar,
+                                                                                functionptr func)
+{
+       int          syncvar;
+       instruction *n_ins;
+
+       if (callee->m->flags & ACC_STATIC) {
+               /* ACONST */
+               syncvar = inline_new_temp_variable(iln->ctx->resultjd, TYPE_ADR);
+
+               n_ins = inline_instruction(iln, ICMD_ACONST, o_iptr);
+               n_ins->sx.val.c.cls = callee->m->clazz;
+               n_ins->dst.varindex = syncvar;
+               n_ins->flags.bits |= INS_FLAG_CLASS;
+       }
+       else {
+               syncvar = instancevar;
+       }
+
+       assert(syncvar != UNUSED);
+
+       /* MONITORENTER / MONITOREXIT */
+
+       n_ins = inline_instruction(iln, ICMD_BUILTIN, o_iptr);
+       n_ins->sx.s23.s3.bte = builtintable_get_internal(func);
+       n_ins->s1.argcount = 1; /* XXX add through-vars */
+       n_ins->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4));
+       n_ins->sx.s23.s2.args[0] = syncvar;
+}
+
+static s4 emit_inlining_prolog(inline_node *iln,
+                                                          inline_node *callee,
+                                                          instruction *o_iptr,
+                                                          s4 *varmap)
+{
+       methodinfo *calleem;
+       methoddesc *md;
+       int i;
+       int localindex;
+       int type;
+       instruction *n_ins;
+       insinfo_inline *insinfo;
+       s4 varindex;
+
+       assert(iln && callee && o_iptr);
+
+       calleem = callee->m;
+       md = calleem->parseddesc;
+
+       /* INLINE_START instruction */
+
+       n_ins = inline_instruction(iln, ICMD_INLINE_START, o_iptr);
+
+       insinfo = (insinfo_inline*) DumpMemory::allocate(sizeof(insinfo_inline));
+       insinfo->method = callee->m;
+       insinfo->outer = iln->m;
+       insinfo->synclocal = callee->synclocal;
+       insinfo->synchronize = callee->synchronize;
+       insinfo->javalocals_start = NULL;
+       insinfo->javalocals_end = NULL;
+
+       /* info about stack vars live at the INLINE_START */
+
+       insinfo->throughcount = callee->n_passthroughcount;
+       insinfo->paramcount = md->paramcount;
+       insinfo->stackvarscount = o_iptr->s1.argcount;
+       insinfo->stackvars = (s4*) DumpMemory::allocate(sizeof(s4) * insinfo->stackvarscount);
+       for (i=0; i<insinfo->stackvarscount; ++i)
+               insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[i]];
+
+       /* info about the surrounding inlining */
+
+       if (iln->inline_start_instruction)
+               insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
+       else
+               insinfo->parent = NULL;
+
+       /* finish the INLINE_START instruction */
+
+       n_ins->sx.s23.s3.inlineinfo = insinfo;
+       callee->inline_start_instruction = n_ins;
+
+       DOLOG( printf("%sprolog: ", iln->indent);
+                  show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
+
+       /* handle parameters for the inlined callee */
+
+       localindex = callee->localsoffset + md->paramslots;
+
+       for (i=md->paramcount-1; i>=0; --i) {
+               assert(iln);
+
+               type = md->paramtypes[i].type;
+
+               localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
+               assert(callee->regdata);
+
+               /* translate the argument variable */
+
+               varindex = varmap[o_iptr->sx.s23.s2.args[i]];
+               assert(varindex != UNUSED);
+
+               /* remove preallocation from the argument variable */
+
+               iln->ctx->resultjd->var[varindex].flags &= ~(PREALLOC | INMEMORY);
+
+               /* check the instance slot against NULL */
+               /* we don't need that for <init> methods, as the verifier  */
+               /* ensures that they are only called for an uninit. object */
+               /* (which may not be NULL).                                */
+
+               if (!callee->isstatic && i == 0 && calleem->name != utf_init) {
+                       assert(type == TYPE_ADR);
+                       n_ins = inline_instruction(iln, ICMD_CHECKNULL, o_iptr);
+                       n_ins->s1.varindex = varindex;
+                       n_ins->dst.varindex = n_ins->s1.varindex;
+               }
+
+               /* store argument into local variable of inlined callee */
+
+               if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != UNUSED)
+               {
+                       /* this value is used in the callee */
+
+                       if (i == 0 && callee->synclocal != UNUSED) {
+                               /* we also need it for synchronization, so copy it */
+                               assert(type == TYPE_ADR);
+                               n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
+                       }
+                       else {
+                               n_ins = inline_instruction(iln, ICMD_ISTORE + type, o_iptr);
+                               n_ins->sx.s23.s3.javaindex = UNUSED;
+                       }
+                       n_ins->s1.varindex = varindex;
+                       n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
+                       assert(n_ins->dst.varindex != UNUSED);
+               }
+               else if (i == 0 && callee->synclocal != UNUSED) {
+                       /* the value is not used inside the callee, but we need it for */
+                       /* synchronization                                             */
+                       /* XXX In this case it actually makes no sense to create a     */
+                       /*     separate synchronization variable.                      */
+
+                       n_ins = inline_instruction(iln, ICMD_NOP, o_iptr);
+               }
+               else {
+                       /* this value is not used, pop it */
+
+                       n_ins = inline_instruction(iln, ICMD_POP, o_iptr);
+                       n_ins->s1.varindex = varindex;
+               }
+
+               DOLOG( printf("%sprolog: ", iln->indent);
+                          show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
+       }
+
+       /* COPY for synchronized instance methods */
+
+       if (callee->synclocal != UNUSED) {
+               n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
+               n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
+               n_ins->dst.varindex = callee->synclocal;
+
+               assert(n_ins->s1.varindex != UNUSED);
+       }
+
+       if (callee->synchronize) {
+               inline_generate_sync_builtin(iln, callee, o_iptr,
+                                                                        (callee->isstatic) ? UNUSED : varmap[o_iptr->sx.s23.s2.args[0]],
+                                                                        LOCK_monitor_enter);
+       }
+
+       /* INLINE_BODY instruction */
+
+       n_ins = inline_instruction(iln, ICMD_INLINE_BODY, callee->jd->basicblocks[0].iinstr);
+       n_ins->sx.s23.s3.inlineinfo = insinfo;
+
+       return 0; /* XXX */
+}
+
+
+static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
+{
+       instruction *n_ins;
+       s4          *jl;
+
+       assert(iln && callee && o_iptr);
+       assert(callee->inline_start_instruction);
+
+       if (callee->synchronize) {
+               inline_generate_sync_builtin(iln, callee, o_iptr,
+                                                                        callee->synclocal,
+                                                                        LOCK_monitor_exit);
+       }
+
+       /* INLINE_END instruction */
+
+       n_ins = inline_instruction(iln, ICMD_INLINE_END, o_iptr);
+       n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
+
+       /* set the javalocals */
+
+       jl = (s4*) DumpMemory::allocate(sizeof(s4) * iln->jd->maxlocals);
+       MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
+       n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
+
+       DOLOG( printf("%sepilog: ", iln->indent);
+                  show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
+}
+
+
+#define TRANSLATE_VAROP(vo)  \
+       n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
+
+
+static void inline_clone_instruction(inline_node *iln,
+                                                                        jitdata *jd,
+                                                                        jitdata *origjd,
+                                                                        s4 *varmap,
+                                                                        instruction *o_iptr,
+                                                                        instruction *n_iptr)
+{
+       icmdtable_entry_t *icmdt;
+       builtintable_entry *bte;
+       methoddesc *md;
+       s4 i, j;
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       inline_node *scope;
+
+       *n_iptr = *o_iptr;
+
+       icmdt = &(icmd_table[o_iptr->opc]);
+
+       switch (icmdt->dataflow) {
+               case DF_0_TO_0:
+                       break;
+
+               case DF_3_TO_0:
+                       TRANSLATE_VAROP(sx.s23.s3);
+               case DF_2_TO_0:
+                       TRANSLATE_VAROP(sx.s23.s2);
+               case DF_1_TO_0:
+                       TRANSLATE_VAROP(s1);
+                       break;
+
+               case DF_2_TO_1:
+                       TRANSLATE_VAROP(sx.s23.s2);
+               case DF_1_TO_1:
+               case DF_COPY:
+               case DF_MOVE:
+                       TRANSLATE_VAROP(s1);
+               case DF_0_TO_1:
+                       TRANSLATE_VAROP(dst);
+                       break;
+
+               case DF_N_TO_1:
+                       n_iptr->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4) * n_iptr->s1.argcount);
+                       for (i=0; i<n_iptr->s1.argcount; ++i) {
+                               n_iptr->sx.s23.s2.args[i] =
+                                       inline_translate_variable(jd, origjd, varmap,
+                                                       o_iptr->sx.s23.s2.args[i]);
+                       }
+                       TRANSLATE_VAROP(dst);
+                       break;
+
+               case DF_INVOKE:
+                       INSTRUCTION_GET_METHODDESC(n_iptr, md);
+clone_call:
+                       n_iptr->s1.argcount += iln->n_passthroughcount;
+                       n_iptr->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4) * n_iptr->s1.argcount);
+                       for (i=0; i<o_iptr->s1.argcount; ++i) {
+                               n_iptr->sx.s23.s2.args[i] =
+                                       inline_translate_variable(jd, origjd, varmap,
+                                                       o_iptr->sx.s23.s2.args[i]);
+                       }
+                       for (scope = iln; scope != NULL; scope = scope->parent) {
+                               for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
+                                       n_iptr->sx.s23.s2.args[i++] =
+                                               scope->parent->varmap[scope->n_passthroughvars[j]];
+                               }
+                       }
+                       if (md->returntype.type != TYPE_VOID)
+                               TRANSLATE_VAROP(dst);
+                       break;
+
+               case DF_BUILTIN:
+                       bte = n_iptr->sx.s23.s3.bte;
+                       md = bte->md;
+                       goto clone_call;
+
+               default:
+                       assert(0);
+       }
+
+       switch (icmdt->controlflow) {
+               case CF_RET:
+                       TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
+                       /* FALLTHROUGH */
+               case CF_IF:
+               case CF_GOTO:
+                       inline_add_block_reference(iln, &(n_iptr->dst.block));
+                       break;
+
+               case CF_JSR:
+                       inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
+                       break;
+
+               case CF_TABLE:
+                       i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
+
+                       table = (branch_target_t*) DumpMemory::allocate(sizeof(branch_target_t) *  i);
+                       MCOPY(table, o_iptr->dst.table, branch_target_t, i);
+                       n_iptr->dst.table = table;
+
+                       while (--i >= 0) {
+                               inline_add_block_reference(iln, &(table->block));
+                               table++;
+                       }
+                       break;
+
+               case CF_LOOKUP:
+                       inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
+
+                       i = n_iptr->sx.s23.s2.lookupcount;
+                       lookup = (lookup_target_t*) DumpMemory::allocate(sizeof(lookup_target_t) * i);
+                       MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
+                       n_iptr->dst.lookup = lookup;
+
+                       while (--i >= 0) {
+                               inline_add_block_reference(iln, &(lookup->target.block));
+                               lookup++;
+                       }
+                       break;
+       }
+
+       /* XXX move this to dataflow section? */
+
+       switch (n_iptr->opc) {
+               case ICMD_ASTORE:
+#if 0
+                       if (n_iptr->flags.bits & INS_FLAG_RETADDR)
+                               inline_add_blocknr_reference(iln, &(n_iptr->sx.s23.s2.retaddrnr));
+#endif
+                       /* FALLTHROUGH! */
+               case ICMD_ISTORE:
+               case ICMD_LSTORE:
+               case ICMD_FSTORE:
+               case ICMD_DSTORE:
+                       stack_javalocals_store(n_iptr, iln->javalocals);
+                       break;
+       }
+}
+
+
+static void inline_rewrite_method(inline_node *iln)
+{
+       basicblock *o_bptr;
+       s4 len;
+       instruction *o_iptr;
+       instruction *n_iptr;
+       inline_node *nextcall;
+       basicblock *n_bptr;
+       inline_block_map *bm;
+       int i;
+       int icount;
+       jitdata *resultjd;
+       jitdata *origjd;
+       char indent[100]; /* XXX debug */
+       s4 retcount;
+       s4 retidx;
+
+       assert(iln);
+
+       resultjd = iln->ctx->resultjd;
+       origjd = iln->jd;
+
+       n_bptr = NULL;
+       nextcall = iln->children;
+
+       /* XXX debug */
+       for (i=0; i<iln->depth; ++i)
+               indent[i] = '\t';
+       indent[i] = 0;
+       iln->indent = indent;
+
+       DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
+                  printf("%s(passthrough: %d+%d)\n",
+                               indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
+                               iln->n_passthroughcount); );
+
+       /* set memory cursors */
+
+       iln->inlined_iinstr_cursor = iln->inlined_iinstr;
+       iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
+
+       /* allocate temporary buffers */
+
+       iln->javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * iln->jd->maxlocals);
+
+       /* loop over basic blocks */
+
+       o_bptr = iln->jd->basicblocks;
+       for (; o_bptr; o_bptr = o_bptr->next) {
+
+               if (o_bptr->flags < BBREACHED) {
+
+                       /* ignore the dummy end block */
+
+                       if (o_bptr->icount == 0 && o_bptr->next == NULL) {
+                               /* enter the following block as translation, for exception handler ranges */
+                               inline_block_translation(iln, o_bptr, iln->inlined_basicblocks_cursor);
+                               continue;
+                       }
+
+                       DOLOG(
+                       printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
+                                       indent,
+                                       o_bptr->nr, o_bptr->flags, o_bptr->type,
+                                       o_bptr->indepth);
+                       method_println(iln->m);
+                       );
+
+                       n_bptr = create_body_block(iln, o_bptr, iln->varmap);
+
+                       /* enter it in the blockmap */
+
+                       inline_block_translation(iln, o_bptr, n_bptr);
+
+                       close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
+                       continue;
+               }
+
+               len = o_bptr->icount;
+               o_iptr = o_bptr->iinstr;
+
+               DOLOG(
+               printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
+                               indent,
+                               o_bptr->nr, o_bptr->flags, o_bptr->type,
+                               o_bptr->indepth);
+               method_println(iln->m);
+               show_basicblock(iln->jd, o_bptr, SHOW_STACK);
+               );
+
+               if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
+                       /* create an inlined clone of this block */
+
+                       n_bptr = create_body_block(iln, o_bptr, iln->varmap);
+                       icount = 0;
+
+                       /* enter it in the blockmap */
+
+                       inline_block_translation(iln, o_bptr, n_bptr);
+
+                       /* initialize the javalocals */
+
+                       MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
+               }
+               else {
+                       s4 *jl;
+
+                       /* continue caller block */
+
+                       n_bptr = iln->inlined_basicblocks_cursor - 1;
+                       icount = n_bptr->icount;
+
+                       /* translate the javalocals */
+
+                       jl = translate_javalocals(iln, o_bptr->javalocals);
+                       iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
+
+                       MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
+               }
+
+               /* iterate over the ICMDs of this block */
+
+               retcount = 0;
+               retidx = UNUSED;
+
+               while (--len >= 0) {
+
+                       DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false,  SHOW_STACK);
+                                  printf("\n") );
+
+                       /* handle calls that will be inlined */
+
+                       if (nextcall && o_iptr == nextcall->callerins) {
+
+                               /* write the inlining prolog */
+
+                               (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
+                               icount += nextcall->prolog_instructioncount;
+
+                               /* end current block, or glue blocks together */
+
+                               n_bptr->icount = icount;
+
+                               if (nextcall->blockbefore) {
+                                       close_prolog_block(iln, n_bptr, nextcall);
+                               }
+                               else {
+                                       /* XXX */
+                               }
+
+                               /* check if the result is a local variable */
+
+                               if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
+                                               && o_iptr->dst.varindex < iln->jd->localcount)
+                               {
+                                       nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
+                               }
+                               else
+                                       nextcall->n_resultlocal = -1;
+
+                               /* set memory pointers in the callee */
+
+                               nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
+                               nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
+
+                               /* recurse */
+
+                               DOLOG( printf("%sentering inline ", indent);
+                                          show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
+
+                               inline_rewrite_method(nextcall);
+
+                               DOLOG( printf("%sleaving inline ", indent);
+                                          show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
+
+                               /* update memory cursors */
+
+                               assert(nextcall->inlined_iinstr_cursor
+                                               <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
+                               assert(nextcall->inlined_basicblocks_cursor
+                                               == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
+                               iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
+                               iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
+
+                               /* start new block, or glue blocks together */
+
+                               if (nextcall->blockafter) {
+                                       n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
+                                       icount = 0;
+                               }
+                               else {
+                                       n_bptr = iln->inlined_basicblocks_cursor - 1;
+                                       icount = n_bptr->icount;
+                                       /* XXX */
+                               }
+
+                               /* emit inlining epilog */
+
+                               emit_inlining_epilog(iln, nextcall, o_iptr);
+                               icount += nextcall->epilog_instructioncount;
+
+                               /* proceed to next call */
+
+                               nextcall = nextcall->next;
+                       }
+                       else {
+                               n_iptr = (iln->inlined_iinstr_cursor++);
+                               assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+
+                               switch (o_iptr->opc) {
+                                       case ICMD_RETURN:
+                                               if (iln->depth == 0)
+                                                       goto default_clone;
+                                               goto return_tail;
+
+                                       case ICMD_IRETURN:
+                                       case ICMD_ARETURN:
+                                       case ICMD_LRETURN:
+                                       case ICMD_FRETURN:
+                                       case ICMD_DRETURN:
+                                               if (iln->depth == 0)
+                                                       goto default_clone;
+                                               retcount = 1;
+                                               retidx = iln->varmap[o_iptr->s1.varindex];
+                                               if (iln->n_resultlocal != -1) {
+                                                       /* store result in a local variable */
+
+                                                       DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
+                                                       /* This relies on the same sequence of types for */
+                                                       /* ?STORE and ?RETURN opcodes.                   */
+                                                       n_iptr->opc = ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN);
+                                                       n_iptr->s1.varindex = retidx;
+                                                       n_iptr->dst.varindex = iln->n_resultlocal;
+                                                       n_iptr->sx.s23.s3.javaindex = UNUSED; /* XXX set real javaindex? */
+
+                                                       retcount = 0;
+                                                       retidx = UNUSED;
+
+                                                       n_iptr = (iln->inlined_iinstr_cursor++);
+                                                       assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+                                                       icount++;
+                                               }
+                                               else if ((retidx < resultjd->localcount && iln->blockafter)
+                                                               || !iln->blockafter) /* XXX do we really always need the MOVE? */
+                                               {
+                                                       /* local must not become outvar, insert a MOVE */
+
+                                                       n_iptr->opc = ICMD_MOVE;
+                                                       n_iptr->s1.varindex = retidx;
+                                                       retidx = inline_new_temp_variable(resultjd,
+                                                                                                                         resultjd->var[retidx].type);
+                                                       n_iptr->dst.varindex = retidx;
+
+                                                       n_iptr = (iln->inlined_iinstr_cursor++);
+                                                       assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
+                                                       icount++;
+                                               }
+return_tail:
+                                               if (iln->blockafter) {
+                                                       n_iptr->opc = ICMD_GOTO;
+                                                       n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
+                                                       inline_add_block_reference(iln, &(n_iptr->dst.block));
+                                               }
+                                               else {
+                                                       n_iptr->opc = ICMD_NOP;
+                                               }
+                                               break;
+#if 0
+                                               if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
+                                                       n_iptr->opc = ICMD_NOP;
+                                                       break;
+                                               }
+                                               goto default_clone;
+                                               break;
+#endif
+
+                                       default:
+default_clone:
+                                               inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
+                               }
+
+                               DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
+                                          printf("\n"););
+
+                               icount++;
+                       }
+
+                       o_iptr++;
+               }
+
+               /* end of basic block */
+
+               if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
+                       close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
+                       n_bptr->icount = icount;
+
+                       DOLOG( printf("closed body block:\n");
+                                  show_basicblock(resultjd, n_bptr, SHOW_STACK); );
+               }
+               else {
+                       n_bptr->icount = icount;
+                       assert(iln->parent);
+                       if (retidx != UNUSED)
+                               iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
+               }
+       }
+
+       bm = iln->ctx->blockmap;
+       for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
+               assert(bm->iln && bm->o_block && bm->n_block);
+               if (bm->iln == iln)
+                       inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block, false);
+       }
+
+#if !defined(NDEBUG)
+       if (iln->refs) {
+               inline_target_ref *ref;
+               ref = iln->refs;
+               while (ref) {
+                       if (!iln->depth || ref->isnumber || *(ref->ref.block) != INLINE_RETURN_REFERENCE(iln)) {
+                               DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
+                                          (void*)*(ref->ref.block)) );
+                               assert(false);
+                       }
+                       ref = ref->next;
+               }
+       }
+#endif
+}
+
+
+static exception_entry * inline_exception_tables(inline_node *iln,
+                                                                                                exception_entry *n_extable,
+                                                                                                exception_entry **prevextable)
+{
+       inline_node *child;
+       inline_node *scope;
+       exception_entry *et;
+
+       assert(iln);
+       assert(n_extable);
+       assert(prevextable);
+
+       child = iln->children;
+       if (child) {
+               do {
+                       n_extable = inline_exception_tables(child, n_extable, prevextable);
+                       child = child->next;
+               } while (child != iln->children);
+       }
+
+       et = iln->jd->exceptiontable;
+       for (; et != NULL; et = et->down) {
+               assert(et);
+               MZERO(n_extable, exception_entry, 1);
+               n_extable->start     = inline_map_block(iln, et->start  , iln);
+               n_extable->end       = inline_map_block(iln, et->end    , iln);
+               n_extable->handler   = inline_map_block(iln, et->handler, iln);
+               n_extable->catchtype = et->catchtype;
+
+               if (*prevextable) {
+                       (*prevextable)->down = n_extable;
+               }
+               *prevextable = n_extable;
+
+               n_extable++;
+       }
+
+       if (iln->handler_monitorexit) {
+               exception_entry **activehandlers;
+
+               MZERO(n_extable, exception_entry, 1);
+               n_extable->start   = iln->inlined_basicblocks;
+               n_extable->end     = iln->inlined_basicblocks_cursor;
+               n_extable->handler = iln->handler_monitorexit;
+               n_extable->catchtype.any = NULL; /* finally */
+
+               if (*prevextable) {
+                       (*prevextable)->down = n_extable;
+               }
+               *prevextable = n_extable;
+
+               n_extable++;
+
+               /* We have to protect the created handler with the same handlers */
+               /* that protect the method body itself.                          */
+
+               for (scope = iln; scope->parent != NULL; scope = scope->parent) {
+
+                       activehandlers = scope->o_handlers;
+                       assert(activehandlers);
+
+                       while (*activehandlers) {
+
+                               assert(scope->parent);
+
+                               MZERO(n_extable, exception_entry, 1);
+                               n_extable->start     = iln->handler_monitorexit;
+                               n_extable->end       = iln->handler_monitorexit + 1; /* XXX ok in this case? */
+                               n_extable->handler   = inline_map_block(scope->parent,
+                                                                                                               (*activehandlers)->handler,
+                                                                                                               scope->parent);
+                               n_extable->catchtype = (*activehandlers)->catchtype;
+
+                               if (*prevextable) {
+                                       (*prevextable)->down = n_extable;
+                               }
+                               *prevextable = n_extable;
+
+                               n_extable++;
+                               activehandlers++;
+                       }
+               }
+       }
+
+       return n_extable;
+}
+
+
+static void inline_locals(inline_node *iln)
+{
+       inline_node *child;
+
+       assert(iln);
+
+       iln->varmap = create_variable_map(iln);
+
+       child = iln->children;
+       if (child) {
+               do {
+                       inline_locals(child);
+                       child = child->next;
+               } while (child != iln->children);
+       }
+
+       if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
+               iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
+       if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
+               iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
+       if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
+               iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
+}
+
+
+static void inline_interface_variables(inline_node *iln)
+{
+       basicblock *bptr;
+       jitdata *resultjd;
+       s4 i;
+       varinfo *v;
+
+       resultjd = iln->ctx->resultjd;
+
+       resultjd->interface_map = (interface_info*) DumpMemory::allocate(sizeof(interface_info) * 5 * iln->ctx->maxinoutdepth);
+       for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
+               resultjd->interface_map[i].flags = UNUSED;
+
+       for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
+               assert(bptr->indepth  <= iln->ctx->maxinoutdepth);
+               assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
+
+               for (i=0; i<bptr->indepth; ++i) {
+                       v = &(resultjd->var[bptr->invars[i]]);
+                       v->flags |= INOUT;
+                       if (v->type == TYPE_RET)
+                               v->flags |= PREALLOC;
+                       else
+                               v->flags &= ~PREALLOC;
+                       v->flags &= ~INMEMORY;
+                       assert(bptr->invars[i] >= resultjd->localcount);
+
+                       if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
+                               resultjd->interface_map[5*i + v->type].flags = v->flags;
+                       }
+                       else {
+                               resultjd->interface_map[5*i + v->type].flags |= v->flags;
+                       }
+               }
+
+               for (i=0; i<bptr->outdepth; ++i) {
+                       v = &(resultjd->var[bptr->outvars[i]]);
+                       v->flags |= INOUT;
+                       if (v->type == TYPE_RET)
+                               v->flags |= PREALLOC;
+                       else
+                               v->flags &= ~PREALLOC;
+                       v->flags &= ~INMEMORY;
+                       assert(bptr->outvars[i] >= resultjd->localcount);
+
+                       if (resultjd->interface_map[5*i + v->type].flags == UNUSED) {
+                               resultjd->interface_map[5*i + v->type].flags = v->flags;
+                       }
+                       else {
+                               resultjd->interface_map[5*i + v->type].flags |= v->flags;
+                       }
+               }
+       }
+}
+
+
+static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
+{
+       basicblock *n_bptr;
+       instruction *n_ins;
+       inline_node *child;
+       builtintable_entry *bte;
+       s4 exvar;
+       s4 syncvar;
+       s4 i;
+
+       child = iln->children;
+       if (child) {
+               do {
+                       inline_write_exception_handlers(master, child);
+                       child = child->next;
+               } while (child != iln->children);
+       }
+
+       if (iln->synchronize) {
+               /* create the monitorexit handler */
+               n_bptr = create_block(master, iln, iln,
+                                                         iln->n_passthroughcount + 1);
+               n_bptr->type = BBTYPE_EXH;
+               n_bptr->flags = BBFINISHED;
+
+               exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
+               n_bptr->invars[iln->n_passthroughcount] = exvar;
+
+               iln->handler_monitorexit = n_bptr;
+
+               /* ACONST / ALOAD */
+
+               n_ins = master->inlined_iinstr_cursor++;
+               if (iln->m->flags & ACC_STATIC) {
+                       n_ins->opc = ICMD_ACONST;
+                       n_ins->sx.val.c.cls = iln->m->clazz;
+                       n_ins->flags.bits = INS_FLAG_CLASS;
+               }
+               else {
+                       n_ins->opc = ICMD_ALOAD;
+                       n_ins->s1.varindex = iln->synclocal;
+                       assert(n_ins->s1.varindex != UNUSED);
+               }
+               /* XXX could be PREALLOCed for  builtin call */
+               syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
+               n_ins->dst.varindex = syncvar;
+               n_ins->line = 0;
+
+               /* MONITOREXIT */
+
+               bte = builtintable_get_internal(LOCK_monitor_exit);
+
+               n_ins = master->inlined_iinstr_cursor++;
+               n_ins->opc = ICMD_BUILTIN;
+               n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
+               n_ins->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4) * n_ins->s1.argcount);
+               n_ins->sx.s23.s2.args[0] = syncvar;
+               for (i=0; i < iln->n_passthroughcount + 1; ++i) {
+                       n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
+               }
+               n_ins->sx.s23.s3.bte = bte;
+               n_ins->line = 0;
+
+               /* ATHROW */
+
+               n_ins = master->inlined_iinstr_cursor++;
+               n_ins->opc = ICMD_ATHROW;
+               n_ins->flags.bits = 0;
+               n_ins->s1.varindex = exvar;
+               n_ins->line = 0;
+
+               /* close basic block */
+
+               close_block(iln, iln, n_bptr, iln->n_passthroughcount);
+               n_bptr->icount = 3;
+       }
+}
+
+
+/* second pass driver *********************************************************/
+
+static bool inline_transform(inline_node *iln, jitdata *jd)
+{
+       instruction *n_ins;
+       basicblock *n_bb;
+       basicblock *n_bptr;
+       exception_entry *n_ext;
+       exception_entry *prevext;
+       codegendata *n_cd;
+       jitdata *n_jd;
+       s4 i;
+#if defined(INLINE_VERIFY_RESULT)
+       static int debug_verify_inlined_code = 1;
+#endif
+#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
+       static int debug_counter = 0;
+#endif
+
+       DOLOG( dump_inline_tree(iln, 0); );
+
+       assert(iln && jd);
+
+       n_ins = (instruction*) DumpMemory::allocate(sizeof(instruction) * iln->cumul_instructioncount);
+       MZERO(n_ins, instruction, iln->cumul_instructioncount);
+       iln->inlined_iinstr = n_ins;
+
+       n_bb = (basicblock*) DumpMemory::allocate(sizeof(basicblock) * iln->cumul_basicblockcount);
+       MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
+       iln->inlined_basicblocks = n_bb;
+
+       iln->ctx->blockmap = (inline_block_map*) DumpMemory::allocate(sizeof(inline_block_map) * iln->cumul_blockmapcount);
+
+       n_jd = jit_jitdata_new(iln->m);
+       n_jd->flags = jd->flags;
+       n_jd->code->optlevel = jd->code->optlevel;
+       iln->ctx->resultjd = n_jd;
+
+       reg_setup(n_jd);
+
+       /* create the local_map */
+
+       n_jd->local_map = (s4*) DumpMemory::allocate(sizeof(s4) *  5 * iln->cumul_maxlocals);
+       for (i=0; i<5*iln->cumul_maxlocals; ++i)
+               n_jd->local_map[i] = UNUSED;
+
+       /* create / coalesce local variables */
+
+       n_jd->varcount = 0;
+       n_jd->vartop = 0;
+       n_jd->var = NULL;
+
+       inline_locals(iln);
+
+       n_jd->localcount = n_jd->vartop;
+
+       /* extra variables for verification (debugging) */
+
+#if defined(INLINE_VERIFY_RESULT)
+       if (debug_verify_inlined_code) {
+               n_jd->vartop   += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
+               if (n_jd->vartop > n_jd->varcount) {
+                       /* XXX why? */
+                       n_jd->var = (varinfo*) DumpMemory::realloc(n_jd->var, sizeof(varinfo) * n_jd->varcount, sizeof(varinfo) * n_jd->vartop);
+                       n_jd->varcount = n_jd->vartop;
+               }
+       }
+#endif /* defined(INLINE_VERIFY_RESULT) */
+
+       /* write inlined code */
+
+       inline_rewrite_method(iln);
+
+       /* create exception handlers */
+
+       inline_write_exception_handlers(iln, iln);
+
+       /* write the dummy end block */
+
+       n_bptr = create_block(iln, iln, iln, 0);
+       n_bptr->flags = BBUNDEF;
+       n_bptr->type = BBTYPE_STD;
+
+       /* store created code in jitdata */
+
+       n_jd->basicblocks = iln->inlined_basicblocks;
+       n_jd->instructioncount = iln->cumul_instructioncount;
+       n_jd->instructions = iln->inlined_iinstr;
+
+       /* link the basic blocks (dummy end block is not counted) */
+
+       n_jd->basicblockcount = (iln->inlined_basicblocks_cursor - iln->inlined_basicblocks) - 1;
+       for (i=0; i<n_jd->basicblockcount + 1; ++i)
+               n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
+       if (i)
+               n_jd->basicblocks[i-1].next = NULL;
+
+       /* check basicblock numbers */
+
+#if !defined(NDEBUG)
+       jit_check_basicblock_numbers(n_jd);
+#endif
+
+       /* create the exception table */
+
+       if (iln->cumul_exceptiontablelength) {
+               exception_entry *tableend;
+
+               n_ext = (exception_entry*) DumpMemory::allocate(sizeof(exception_entry) * iln->cumul_exceptiontablelength);
+               prevext = NULL;
+               tableend = inline_exception_tables(iln, n_ext, &prevext);
+               assert(tableend == n_ext + iln->cumul_exceptiontablelength);
+               if (prevext)
+                       prevext->down = NULL;
+
+               n_jd->exceptiontablelength = iln->cumul_exceptiontablelength;
+               n_jd->exceptiontable = n_ext;
+       }
+       else {
+               n_ext = NULL;
+       }
+
+       /*******************************************************************************/
+
+       n_cd = n_jd->cd;
+       memcpy(n_cd, jd->cd, sizeof(codegendata));
+
+       n_cd->method = NULL; /* XXX */
+       n_jd->maxlocals = iln->cumul_maxlocals;
+       n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
+
+       inline_post_process(n_jd);
+
+       inline_interface_variables(iln);
+
+       /* for debugging, verify the inlined result */
+
+#if defined(INLINE_VERIFY_RESULT)
+       if (debug_verify_inlined_code) {
+               debug_verify_inlined_code = 0;
+               DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
+               if (!typecheck(n_jd)) {
+                       exceptions_clear_exception();
+                       DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
+                       return false;
+               }
+               else {
+                       DOLOG( printf("VERIFICATION PASSED.\n") );
+               }
+               debug_verify_inlined_code = 1;
+       }
+#endif /* defined(INLINE_VERIFY_RESULT) */
+
+       /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
+
+       n_jd->rd->freemem = (s4*) DumpMemory::allocate(sizeof(s4) * (iln->ctx->maxinoutdepth + 1000)) /* XXX max vars/block */;
+
+#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
+       if (   (n_jd->instructioncount >= opt_InlineMinSize)
+               && (n_jd->instructioncount <= opt_InlineMaxSize))
+       {
+          if (debug_counter < opt_InlineCount)
+#endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */
+          {
+                       /* install the inlined result */
+
+                       *jd->code = *n_jd->code;
+                       n_jd->code = jd->code;
+                       *jd = *n_jd;
+
+                       /* statistics and logging */
+
+#if !defined(NDEBUG)
+                       inline_stat_roots++;
+
+                       DOLOG_SHORT(
+                       printf("==== %d.INLINE ==================================================================\n",
+                               debug_counter);
+                       printf("\ninline tree:\n");
+                       dump_inline_tree(iln, 0);
+                       n_jd->flags |= JITDATA_FLAG_SHOWINTERMEDIATE | JITDATA_FLAG_SHOWDISASSEMBLE;
+                       /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
+                       printf("-------- DONE -----------------------------------------------------------\n");
+                       fflush(stdout);
+                       );
+#endif
+          }
+
+#if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
+               debug_counter++;
+       }
+#endif
+       return true;
+}
+
+
+/******************************************************************************/
+/* FIRST PASS: build inlining tree                                            */
+/******************************************************************************/
+
+
+/* inline_pre_parse_heuristics *************************************************
+
+   Perform heuristic checks whether a call site should be inlined.
+   These checks are evaluated before the callee has been parsed and analysed.
+
+   IN:
+       caller...........inlining node of the caller
+          callee...........the called method
+          site.............information on the call site
+
+   RETURN VALUE:
+       true........consider for inlining
+          false.......don't inline
+
+*******************************************************************************/
+
+static bool inline_pre_parse_heuristics(const inline_node *caller,
+                                                                               const methodinfo *callee,
+                                                                               inline_site *site)
+{
+#if defined(INLINE_MAX_DEPTH)
+       if (caller->depth >= INLINE_MAX_DEPTH)
+               return false;
+#endif
+
+       return true;
+}
+
+
+/* inline_post_parse_heuristics ************************************************
+
+   Perform heuristic checks whether a call site should be inlined.
+   These checks are evaluated after the callee has been parsed and analysed.
+
+   IN:
+       caller...........inlining node of the caller (const)
+          callee...........the called method (const)
+
+   RETURN VALUE:
+          true........consider for inlining
+          false.......don't inline
+
+*******************************************************************************/
+
+static bool inline_post_parse_heuristics(const inline_node *caller,
+                                                                                const inline_node *callee)
+{
+       return true;
+}
+
+
+/* inline_afterwards_heuristics ************************************************
+
+   Perform heuristic checks whether a call site should be inlined.
+   These checks are evaluated after the inlining plan for the callee has
+   been made.
+
+   IN:
+       caller...........inlining node of the caller (const)
+          callee...........the called method (const)
+
+   RETURN VALUE:
+          true........consider for inlining
+          false.......don't inline
+
+*******************************************************************************/
+
+static bool inline_afterwards_heuristics(const inline_node *caller,
+                                                                                const inline_node *callee)
+{
+       inline_node *cumulator;
+
+#if defined(INLINE_DEPTH_FIRST)
+       cumulator = caller;
+#else
+       cumulator = caller->ctx->master;
+#endif
+
+       if (0
+#if defined(INLINE_MAX_BLOCK_EXPANSION)
+               || (cumulator->cumul_basicblockcount + callee->cumul_basicblockcount
+                       > INLINE_MAX_BLOCK_EXPANSION*caller->ctx->master->jd->basicblockcount)
+#endif
+#if defined(INLINE_MAX_ICMD_EXPANSION)
+               || (cumulator->cumul_instructioncount + callee->cumul_instructioncount
+                       > INLINE_MAX_ICMD_EXPANSION*caller->ctx->master->jd->instructioncount)
+#endif
+          )
+       {
+               return false;
+       }
+
+       return true;
+}
+
+
+/* inline_is_monomorphic *******************************************************
+
+   Check if the given call site can be proven to be monomorphic.
+
+   IN:
+          callee...........the called method
+          call.............the invocation instruction
+
+   OUT:
+       site->speculative.....flags whether the inlining is speculative
+                                (only defined if return value is true)
+
+   RETURN VALUE:
+       true if the call site is (currently) monomorphic,
+          false if not or unknown
+
+*******************************************************************************/
+
+static bool inline_is_monomorphic(const methodinfo *callee,
+                                                                 const instruction *call,
+                                                                 inline_site *site)
+{
+       if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
+                               || call->opc == ICMD_INVOKESPECIAL))
+       {
+               site->speculative = false;
+               return true;
+       }
+
+       /* XXX search single implementation for abstract monomorphics */
+
+       if ((callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED
+                                       | ACC_ABSTRACT))
+                       == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED))
+       {
+               if (1) {
+                       DOLOG( printf("SPECULATIVE INLINE: "); method_println((methodinfo*)callee); );
+                       site->speculative = true;
+
+                       return true;
+               }
+       }
+
+       /* possibly polymorphic call site */
+
+       return false;
+}
+
+
+/* inline_can_inline ***********************************************************
+
+   Check if inlining of the given call site is possible.
+
+   IN:
+       caller...........inlining node of the caller
+          callee...........the called method
+          call.............the invocation instruction
+
+   OUT:
+       site->speculative.....flags whether the inlining is speculative
+                                (only defined if return value is true)
+
+   RETURN VALUE:
+       true if inlining is possible, false if not
+
+*******************************************************************************/
+
+static bool inline_can_inline(const inline_node *caller,
+                                                         const methodinfo *callee,
+                                                         const instruction *call,
+                                                         inline_site *site)
+{
+       const inline_node *active;
+
+       /* cannot inline native methods */
+
+       if (callee->flags & ACC_NATIVE)
+               return false;
+
+       /* cannot inline possibly polymorphic calls */
+
+       if (!inline_is_monomorphic(callee, call, site))
+               return false;
+
+       /* cannot inline recursive calls */
+
+       for (active = caller; active; active = active->parent) {
+               if (callee == active->m) {
+                       DOLOG( printf("RECURSIVE!\n") );
+                       return false;
+               }
+       }
+
+       /* inlining is possible */
+
+       return true;
+}
+
+
+/* inline_create_callee_node ***************************************************
+
+   Create an inlining node for the given callee.
+
+   IN:
+          caller...........inlining node of the caller (const)
+          callee...........the called method
+
+   RETURN VALUE:
+       the new inlining node
+
+*******************************************************************************/
+
+static inline_node * inline_create_callee_node(const inline_node *caller,
+                                                                                          methodinfo *callee)
+{
+       inline_node *cn;              /* the callee inline_node */
+
+       cn = (inline_node*) DumpMemory::allocate(sizeof(inline_node));
+       MZERO(cn, inline_node, 1);
+
+       cn->depth = caller->depth + 1;
+       cn->ctx = caller->ctx;
+       cn->m = callee;
+       cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
+       cn->isstatic = (callee->flags & ACC_STATIC);
+
+       return cn;
+}
+
+
+/* inline_set_callee_properties ************************************************
+
+   Set properties of the inlined call site.
+
+   IN:
+       caller...........inlining node of the caller (const)
+          cn...............the called method
+          site.............info about the call site (const)
+
+   OUT:
+       *cn..............has the properties set
+
+*******************************************************************************/
+
+static void inline_set_callee_properties(const inline_node *caller,
+                                                                                inline_node *cn,
+                                                                                const inline_site *site)
+{
+       s4           argi;
+       s4           i, j;
+       basicblock  *bptr;
+
+       /* set info about the call site */
+
+       cn->callerblock = site->bptr;
+       cn->callerins = site->iptr;
+       cn->callerpc = site->pc;
+       cn->o_handlers = site->handlers;
+       cn->n_handlercount = caller->n_handlercount + site->nhandlers;
+
+       /* determine if we need basic block boundaries before/after */
+
+       cn->blockbefore = false;
+       cn->blockafter = false;
+
+       if (cn->jd->branchtoentry)
+               cn->blockbefore = true;
+
+       if (cn->jd->branchtoend)
+               cn->blockafter = true;
+
+       if (cn->jd->returncount > 1)
+               cn->blockafter = true;
+
+       /* XXX make safer and reusable (maybe store last real block) */
+       for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
+               ;
+
+       if (cn->jd->returnblock != bptr)
+               cn->blockafter = true;
+
+       /* info about the callee */
+
+       cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
+       cn->prolog_instructioncount = cn->m->parseddesc->paramcount + 2;
+       cn->epilog_instructioncount = 1; /* INLINE_END */
+       cn->extra_instructioncount = 0;
+
+       /* we need a CHECKNULL for instance methods, except for <init> */
+
+       if (!cn->isstatic && cn->m->name != utf_init)
+               cn->prolog_instructioncount += 1;
+
+       /* deal with synchronized callees */
+
+       if (cn->synchronize) {
+               methoddesc         *md;
+               builtintable_entry *bte;
+
+               /* we need basic block boundaries because of the handler */
+
+               cn->blockbefore = true;
+               cn->blockafter = true;
+
+               /* for synchronized static methods                 */
+               /* we need an ACONST, MONITORENTER in the prolog   */
+               /* and ACONST, MONITOREXIT in the epilog           */
+
+               /* for synchronized instance methods               */
+               /* we need an COPY, MONITORENTER in the prolog     */
+               /* and MONITOREXIT in the epilog                   */
+
+               if (cn->isstatic) {
+                       cn->prolog_instructioncount += 2;
+                       cn->epilog_instructioncount += 2;
+               }
+               else {
+                       cn->prolog_instructioncount += 2;
+                       cn->epilog_instructioncount += 1;
+                       cn->localsoffset += 1;
+               }
+
+               /* and exception handler */
+               /* ALOAD, builtin_monitorexit, ATHROW */
+
+               cn->extra_instructioncount += 3;
+
+               /* exception table entries */
+
+               cn->extra_exceptiontablelength = 1 + cn->n_handlercount;
+
+               /* add exception handler block */
+
+               cn->cumul_basicblockcount_root++;
+
+               /* we must call the builtins */
+
+               bte = builtintable_get_internal(LOCK_monitor_enter);
+               md = bte->md;
+               if (md->memuse > cn->regdata->memuse)
+                       cn->regdata->memuse = md->memuse;
+               if (md->argintreguse > cn->regdata->argintreguse)
+                       cn->regdata->argintreguse = md->argintreguse;
+
+               bte = builtintable_get_internal(LOCK_monitor_exit);
+               md = bte->md;
+               if (md->memuse > cn->regdata->memuse)
+                       cn->regdata->memuse = md->memuse;
+               if (md->argintreguse > cn->regdata->argintreguse)
+                       cn->regdata->argintreguse = md->argintreguse;
+       }
+
+       /* determine pass-through variables */
+
+       i = site->iptr->s1.argcount - cn->m->parseddesc->paramcount; /* max # of pass-though vars */
+
+       cn->n_passthroughvars = (s4*) DumpMemory::allocate(sizeof(s4) * i);
+       j = 0;
+       for (argi = site->iptr->s1.argcount - 1; argi >= cn->m->parseddesc->paramcount; --argi) {
+               s4 idx = site->iptr->sx.s23.s2.args[argi];
+               if (idx >= caller->jd->localcount) {
+                       cn->n_passthroughvars[j] = idx;
+                       j++;
+               }
+               else {
+                       DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
+               }
+       }
+       assert(j <= i);
+       cn->n_selfpassthroughcount = j;
+       cn->n_passthroughcount = caller->n_passthroughcount + cn->n_selfpassthroughcount;
+}
+
+
+/* inline_cumulate_counters ****************************************************
+
+   Cumulate counters after a node has been decided to become inlined.
+
+   IN:
+       caller...........inlining node of the caller
+          callee...........inlining node of the callee (const)
+
+   OUT:
+       *caller..........gets cumulated values added
+
+*******************************************************************************/
+
+static void inline_cumulate_counters(inline_node *caller,
+                                                                        const inline_node *cn)
+{
+       caller->cumul_instructioncount += cn->prolog_instructioncount;
+       caller->cumul_instructioncount += cn->epilog_instructioncount;
+       caller->cumul_instructioncount += cn->extra_instructioncount;
+       caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
+
+       caller->cumul_basicblockcount += cn->cumul_basicblockcount;
+       caller->cumul_basicblockcount_root += cn->cumul_basicblockcount_root;
+       caller->cumul_blockmapcount += cn->cumul_blockmapcount;
+       caller->cumul_exceptiontablelength += cn->cumul_exceptiontablelength;
+       caller->cumul_exceptiontablelength += cn->extra_exceptiontablelength;
+
+       if (cn->cumul_maxlocals > caller->cumul_maxlocals)
+               caller->cumul_maxlocals = cn->cumul_maxlocals;
+
+       /* XXX extra block after inlined call */
+       if (cn->blockafter) {
+               caller->cumul_basicblockcount += 1;
+               caller->cumul_blockmapcount += 1;
+       }
+}
+
+
+/* inline_analyse_callee *******************************************************
+
+   Analyse an inlining candidate callee.
+
+   IN:
+       caller...........inlining node of the caller
+          callee...........the called method
+          site.............info about the call site
+
+   OUT:
+       site->inlined....true if the callee has been selected for inlining
+
+   RETURN VALUE:
+       the inline node of the callee, or
+       NULL if an error has occurred (don't use the inlining plan in this case)
+
+*******************************************************************************/
+
+static inline_node * inline_analyse_callee(inline_node *caller,
+                                                                                  methodinfo *callee,
+                                                                                  inline_site *site)
+{
+       inline_node *cn;              /* the callee inline_node */
+
+       /* create an inline tree node */
+
+       cn = inline_create_callee_node(caller, callee);
+
+       /* get the intermediate representation of the callee */
+
+       if (!inline_jit_compile(cn))
+               return NULL;
+
+       /* evaluate heuristics after parsing the callee */
+
+       if (!inline_post_parse_heuristics(caller, cn))
+               return cn;
+
+       /* the call site will be inlined */
+
+       site->inlined = true;
+
+       /* set info about the call site */
+
+       inline_set_callee_properties(caller, cn, site);
+
+       /* insert the node into the inline tree */
+
+       inline_insert_inline_node(caller, cn);
+
+       /* analyse recursively */
+
+       if (!inline_analyse_code(cn))
+               return NULL;
+
+       if (!inline_afterwards_heuristics(caller, cn)) {
+#if defined(INLINE_CANCEL_ON_THRESHOLD)
+               return NULL;
+#else
+               inline_remove_inline_node(caller, cn);
+               caller->ctx->stopped = true;
+               site->inlined = false;
+               return cn;
+#endif
+       }
+
+       /* cumulate counters */
+
+#if defined(INLINE_DEPTH_FIRST)
+       inline_cumulate_counters(caller, cn);
+#endif
+
+#if defined(INLINE_BREADTH_FIRST)
+       while (caller) {
+               inline_cumulate_counters(caller, cn);
+               caller = caller->parent;
+       }
+#endif
+
+       return cn;
+}
+
+
+/* inline_process_candidate ****************************************************
+
+   Process a selected inlining candidate.
+
+   IN:
+       cand.............the candidate
+
+   RETURN VALUE:
+       true........everything ok
+          false.......an error has occurred, don't use the plan
+
+*******************************************************************************/
+
+static bool inline_process_candidate(inline_candidate *cand)
+{
+       inline_node *cn;
+
+       cn = inline_analyse_callee(cand->caller,
+                                                          cand->callee,
+                                                          &(cand->site));
+
+       if (!cn)
+               return false;
+
+       if (!cand->site.inlined)
+               return true;
+
+       /* store assumptions */
+
+       if (cand->site.speculative)
+               method_add_assumption_monomorphic(cand->callee, cand->caller->ctx->master->m);
+
+       return true;
+}
+
+
+/* inline_analyse_code *********************************************************
+
+   Analyse the intermediate code of the given inlining node.
+
+   IN:
+       iln..............the inlining node
+
+   OUT:
+       *iln.............the inlining plan
+
+   RETURN VALUE:
+       true........everything ok
+          false.......an error has occurred, don't use the plan
+
+*******************************************************************************/
+
+static bool inline_analyse_code(inline_node *iln)
+{
+       methodinfo *m;
+       basicblock *bptr;
+       s4 len;
+       instruction *iptr;
+       methodinfo *callee;
+       exception_entry **handlers;
+       exception_entry *ex;
+       s4 nhandlers;
+       s4 blockendpc;
+       jitdata *mjd;
+       inline_site site;
+
+       assert(iln);
+
+       m = iln->m;
+       mjd = iln->jd;
+
+       /* initialize cumulative counters */
+
+       iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
+       iln->cumul_exceptiontablelength += mjd->exceptiontablelength;
+
+       /* iterate over basic blocks */
+
+       blockendpc = 0;
+
+       for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
+
+               /* count the block */
+               /* ignore dummy end blocks (but count them for the blockmap) */
+
+               iln->cumul_blockmapcount++;
+               if ((bptr != mjd->basicblocks || iln->blockbefore)
+                               &&
+                       (bptr->icount > 0 || bptr->next != NULL))
+                       iln->cumul_basicblockcount++;
+
+               /* skip dead code */
+
+               if (bptr->flags < BBREACHED)
+                       continue;
+
+               /* allocate the buffer of active exception handlers */
+               /* XXX this wastes some memory, but probably it does not matter */
+
+               handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (mjd->exceptiontablelength + 1));
+
+               /* determine the active exception handlers for this block     */
+               /* XXX maybe the handlers of a block should be part of our IR */
+               /* XXX this should share code with the type checkers          */
+               nhandlers = 0;
+               for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
+                       if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
+                               handlers[nhandlers++] = ex;
+                       }
+               }
+               handlers[nhandlers] = NULL;
+
+               len = bptr->icount;
+               iptr = bptr->iinstr;
+
+               blockendpc += len;
+               iln->cumul_instructioncount += len;
+
+               /* iterate over the instructions of the block */
+
+               for (; --len >= 0; ++iptr) {
+
+                       switch (iptr->opc) {
+                               case ICMD_INVOKEVIRTUAL:
+                               case ICMD_INVOKESPECIAL:
+                               case ICMD_INVOKESTATIC:
+                               case ICMD_INVOKEINTERFACE:
+
+                                       if (!INSTRUCTION_IS_UNRESOLVED(iptr) && !iln->ctx->stopped) {
+                                               callee = iptr->sx.s23.s3.fmiref->p.method;
+
+                                               if (inline_can_inline(iln, callee, iptr, &site)) {
+                                                       site.inlined = false;
+                                                       site.bptr = bptr;
+                                                       site.iptr = iptr;
+                                                       site.pc = blockendpc - len - 1;
+                                                       site.handlers = handlers;
+                                                       site.nhandlers = nhandlers;
+
+                                                       if (inline_pre_parse_heuristics(iln, callee, &site)) {
+#if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
+                                                               inline_add_candidate(iln->ctx, iln, callee, &site);
+#else
+                                                               inline_candidate cand;
+                                                               cand.caller = iln;
+                                                               cand.callee = callee;
+                                                               cand.site   = site;
+
+                                                               if (!inline_process_candidate(&cand))
+                                                                       return false;
+#endif
+                                                       }
+                                               }
+                                       }
+                                       break;
+
+                               case ICMD_RETURN:
+                               case ICMD_IRETURN:
+                               case ICMD_ARETURN:
+                               case ICMD_LRETURN:
+                               case ICMD_FRETURN:
+                               case ICMD_DRETURN:
+                                       /* extra ICMD_MOVE may be necessary */
+                                       iln->cumul_instructioncount++;
+                                       break;
+                       }
+               }
+
+               /* end of basic block */
+       }
+
+       return true;
+}
+
+
+static void inline_cumulate_counters_recursive(inline_node *iln)
+{
+       inline_node *child;
+
+       child = iln->children;
+       if (child) {
+               do {
+                       inline_cumulate_counters_recursive(child);
+                       inline_cumulate_counters(iln, child);
+                       child = child->next;
+               } while (child != iln->children);
+       }
+}
+
+
+/* inline_make_inlining_plan ***************************************************
+
+   Make an inlining plan for the given root node
+
+   IN:
+       iln..............the root node
+
+   OUT:
+       *iln.............the inlining plan
+
+   RETURN VALUE:
+       true........everything ok
+          false.......an error has occurred, don't use the plan
+
+*******************************************************************************/
+
+#if defined(INLINE_KNAPSACK)
+static bool inline_make_inlining_plan(inline_node *iln)
+{
+       inline_candidate *cand;
+#if defined(INLINE_COST_BUDGET)
+       s4 budget = INLINE_COST_BUDGET;
+#   define BUDGETMEMBER cost
+#endif
+#if defined(INLINE_WEIGHT_BUDGET)
+       double budget = INLINE_WEIGHT_BUDGET;
+#   define BUDGETMEMBER weight
+#endif
+
+       inline_analyse_code(iln);
+
+       DOLOG( printf("candidates in "); method_println(iln->m);
+                  inline_candidates_println(iln->ctx); );
+
+       while ((cand = inline_pick_best_candidate(iln->ctx)) != NULL)
+       {
+               if (cand->BUDGETMEMBER <= budget) {
+                       DOLOG( printf("    picking: "); inline_candidate_println(cand); );
+
+                       if (!inline_process_candidate(cand))
+                               return false;
+
+#if !defined(INLINE_ADD_NEGATIVE_TO_BUDGET)
+                       if (cand->BUDGETMEMBER > 0)
+#endif
+                               budget -= cand->BUDGETMEMBER;
+               }
+       }
+
+       inline_cumulate_counters_recursive(iln);
+
+       return true;
+}
+#endif /* defined(INLINE_KNAPSACK) */
+
+
+#if defined(INLINE_DEPTH_FIRST)
+static bool inline_make_inlining_plan(inline_node *iln)
+{
+       return inline_analyse_code(iln);
+}
+#endif /* defined(INLINE_DEPTH_FIRST) */
+
+
+#if defined(INLINE_BREADTH_FIRST)
+static bool inline_make_inlining_plan(inline_node *iln)
+{
+       inline_candidate *cand;
+
+       inline_analyse_code(iln);
+
+       DOLOG( printf("candidates in "); method_println(iln->m);
+                  inline_candidates_println(iln->ctx); );
+
+       while (!iln->ctx->stopped
+                  && (cand = inline_pick_best_candidate(iln->ctx)) != NULL)
+       {
+               DOLOG( printf("    picking: "); inline_candidate_println(cand); );
+
+               if (!inline_process_candidate(cand))
+                       return false;
+       }
+
+       return true;
+}
+#endif /* defined(INLINE_BREADTH_FIRST) */
+
+
+/* statistics *****************************************************************/
+
+#if defined(INLINE_STATISTICS)
+static void inline_gather_statistics_recursive(inline_node *iln)
+{
+       inline_node *child;
+
+       inline_stat_inlined_nodes++;
+
+       if (iln->depth > inline_stat_max_depth)
+               inline_stat_max_depth++;
+
+       child = iln->children;
+       if (child) {
+               do {
+                       inline_gather_statistics_recursive(child);
+                       child = child->next;
+               } while (child != iln->children);
+       }
+}
+#endif /* defined(INLINE_STATISTICS) */
+
+
+#if defined(INLINE_STATISTICS)
+static void inline_gather_statistics(inline_node *iln)
+{
+       inline_stat_roots_transformed++;
+
+       inline_gather_statistics_recursive(iln);
+}
+#endif /* defined(INLINE_STATISTICS) */
+
+
+/* post processing ************************************************************/
+
+#define POSTPROCESS_SRC(varindex)  live[varindex]--
+#define POSTPROCESS_DST(varindex)  live[varindex]++
+
+#define POSTPROCESS_SRCOP(s)  POSTPROCESS_SRC(iptr->s.varindex)
+#define POSTPROCESS_DSTOP(d)  POSTPROCESS_DST(iptr->d.varindex)
+
+#define MARKSAVED(varindex)  jd->var[varindex].flags |= SAVEDVAR
+
+#define MARK_ALL_SAVED                                               \
+    do {                                                             \
+        for (i=0; i<jd->vartop; ++i)                                 \
+            if (live[i])                                             \
+                MARKSAVED(i);                                        \
+    } while (0)
+
+static void inline_post_process(jitdata *jd)
+{
+       codeinfo   *code;
+       basicblock *bptr;
+       instruction *iptr;
+       instruction *iend;
+       s4 i;
+       icmdtable_entry_t *icmdt;
+       s4 *live;
+       methoddesc *md;
+       builtintable_entry *bte;
+
+       /* Get required compiler data. */
+
+       code = jd->code;
+
+       /* reset the SAVEDVAR flag of all variables */
+
+       for (i=0; i<jd->vartop; ++i)
+               jd->var[i].flags &= ~SAVEDVAR;
+
+       /* allocate the life counters */
+
+       live = (s4*) DumpMemory::allocate(sizeof(s4) * jd->vartop);
+       MZERO(live, s4, jd->vartop);
+
+       /* iterate over all basic blocks */
+
+       for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
+               if (bptr->flags < BBREACHED)
+                       continue;
+
+               /* make invars live */
+
+               for (i=0; i<bptr->indepth; ++i)
+                       POSTPROCESS_DST(bptr->invars[i]);
+
+               iptr = bptr->iinstr;
+               iend = iptr + bptr->icount;
+
+               for (; iptr < iend; ++iptr) {
+
+                       icmdt = &(icmd_table[iptr->opc]);
+
+                       switch (icmdt->dataflow) {
+                               case DF_3_TO_0:
+                                       POSTPROCESS_SRCOP(sx.s23.s3);
+                               case DF_2_TO_0:
+                                       POSTPROCESS_SRCOP(sx.s23.s2);
+                               case DF_1_TO_0:
+                                       POSTPROCESS_SRCOP(s1);
+                               case DF_0_TO_0:
+                                       if (icmdt->flags & ICMDTABLE_CALLS) {
+                                               code_unflag_leafmethod(code);
+                                               MARK_ALL_SAVED;
+                                       }
+                                       break;
+
+                               case DF_2_TO_1:
+                                       POSTPROCESS_SRCOP(sx.s23.s2);
+                               case DF_1_TO_1:
+                               case DF_MOVE:
+                                       POSTPROCESS_SRCOP(s1);
+                               case DF_0_TO_1:
+                                       if (icmdt->flags & ICMDTABLE_CALLS) {
+                                               code_unflag_leafmethod(code);
+                                               MARK_ALL_SAVED;
+                                       }
+                               case DF_COPY:
+                                       POSTPROCESS_DSTOP(dst);
+                                       break;
+
+                               case DF_N_TO_1:
+                                       for (i=0; i<iptr->s1.argcount; ++i) {
+                                               POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
+                                       }
+                                       if (icmdt->flags & ICMDTABLE_CALLS) {
+                                               code_unflag_leafmethod(code);
+                                               MARK_ALL_SAVED;
+                                       }
+                                       POSTPROCESS_DSTOP(dst);
+                                       break;
+
+                               case DF_INVOKE:
+                                       INSTRUCTION_GET_METHODDESC(iptr, md);
+               post_process_call:
+                                       code_unflag_leafmethod(code);
+                                       for (i=0; i<md->paramcount; ++i) {
+                                               POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
+                                       }
+                                       for (; i<iptr->s1.argcount; ++i) {
+                                               MARKSAVED(iptr->sx.s23.s2.args[i]);
+                                       }
+                                       if (md->returntype.type != TYPE_VOID)
+                                               POSTPROCESS_DSTOP(dst);
+                                       break;
+
+                               case DF_BUILTIN:
+                                       bte = iptr->sx.s23.s3.bte;
+                                       md = bte->md;
+                                       goto post_process_call;
+
+                               default:
+                                       assert(0);
+                       }
+
+               } /* end instruction loop */
+
+               /* consume outvars */
+
+               for (i=0; i<bptr->outdepth; ++i)
+                       POSTPROCESS_SRC(bptr->outvars[i]);
+
+#if !defined(NDEBUG)
+               for (i=jd->localcount; i < jd->vartop; ++i)
+                       assert(live[i] == 0);
+#endif
+
+       } /* end basic block loop */
+}
+
+
+/* inline_create_root_node *****************************************************
+
+   Create the root node of the inlining tree.
+
+   IN:
+          jd...............the current jitdata of the root method
+
+   RETURN VALUE:
+       the root node of the inlining tree
+
+*******************************************************************************/
+
+static inline_node * inline_create_root_node(jitdata *jd)
+{
+       inline_node *iln;
+
+       iln = (inline_node*) DumpMemory::allocate(sizeof(inline_node));
+       MZERO(iln, inline_node, 1);
+
+       iln->m = jd->m;
+       iln->jd = jd;
+       iln->regdata = jd->rd;
+
+       iln->blockbefore = true;
+       iln->blockafter = true;
+
+       iln->cumul_instructioncount = 0;
+       iln->cumul_basicblockcount = 1 /* dummy end block */;
+
+       /* create inlining context */
+
+       iln->ctx = (inline_context*) DumpMemory::allocate(sizeof(inline_context));
+       MZERO(iln->ctx, inline_context, 1);
+       iln->ctx->master = iln;
+       iln->ctx->next_debugnr = 1; /* XXX debug */
+
+       return iln;
+}
+
+
+/******************************************************************************/
+/* MAIN DRIVER FUNCTION                                                       */
+/******************************************************************************/
+
+bool inline_inline(jitdata *jd)
+{
+       inline_node *iln;
+
+       DOLOG( printf("==== INLINE ==================================================================\n");
+                  show_method(jd, SHOW_STACK); );
+
+#if defined(INLINE_STATISTICS)
+       inline_stat_roots++;
+#endif
+
+       iln = inline_create_root_node(jd);
+
+       if (inline_make_inlining_plan(iln)) {
+
+               /* add blocks to the root node */
+
+               iln->cumul_basicblockcount += iln->cumul_basicblockcount_root;
+               iln->cumul_blockmapcount   += iln->cumul_basicblockcount_root;
+
+               DOLOG( printf("==== INLINE TRANSFORM ========================================================\n"); );
+
+               if (iln->children)
+                       inline_transform(iln, jd);
+
+#if defined(INLINE_STATISTICS)
+               inline_gather_statistics(iln);
+#endif
+       }
+
+       DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
+                  fflush(stdout); );
+
+       return true;
+}
+
+#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/jit/inline/inline.h b/src/vm/jit/inline/inline.h
deleted file mode 100644 (file)
index 629f649..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* src/vm/jit/inline/inline.h - code inliner
-
-   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 _INLINE_H
-#define _INLINE_H
-
-#include "config.h"
-
-#include <stdbool.h>
-
-#include "vm/jit/jit.hpp"
-
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-bool inline_inline(jitdata *jd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _INLINE_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/jit/inline/inline.hpp b/src/vm/jit/inline/inline.hpp
new file mode 100644 (file)
index 0000000..373de8f
--- /dev/null
@@ -0,0 +1,62 @@
+/* src/vm/jit/inline/inline.h - code inliner
+
+   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 _INLINE_H
+#define _INLINE_H
+
+#include "config.h"
+
+#include <stdbool.h>
+
+#include "vm/jit/jit.hpp"
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool inline_inline(jitdata *jd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _INLINE_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 62b3651aea5a9cc5ce4792565474c30e682eed75..0598774c7e2774b9f93cdb14f2a6d31d01166037 100644 (file)
@@ -55,7 +55,7 @@ libintrp_la_SOURCES = \
        codegen.c \
        codegen.h \
        disasm.c \
-       disass.c \
+       disass.cpp \
        dynamic-super.c \
        engine1.c \
        engine2.c \
index d84edec56ce7ac0d2104491959b888215cb98aa7..dc31a95d3026280f8106ed5f35b2999ad77256e6 100644 (file)
@@ -35,7 +35,7 @@
 
 #include "vm/jit/builtin.hpp"
 #include "vm/class.hpp"
-#include "vm/linker.h"
+#include "vm/linker.hpp"
 #include "vm/loader.hpp"
 #include "vm/options.h"
 
index ddb68c7303ef0dc485fc3c82205b5368bdddfa23..4fbca4a70d15856dfe575b7af0675374fcef8cea 100644 (file)
@@ -58,7 +58,7 @@
 #include "vm/jit/codegen-common.hpp"
 #include "vm/jit/dseg.h"
 #include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/patcher.h"
 #include "vm/jit/stack.h"
 #include "vm/jit/stacktrace.hpp"
diff --git a/src/vm/jit/intrp/disass.c b/src/vm/jit/intrp/disass.c
deleted file mode 100644 (file)
index 4219f00..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/* src/vm/jit/intrp/disass.c - disassembler wrapper for interpreter
-
-   Copyright (C) 1996-2005, 2006, 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 <stdio.h>
-
-#include "vm/types.h"
-
-#include "vm/jit/intrp/intrp.h"
-
-
-/* function disassinstr ********************************************************
-
-       outputs a disassembler listing of one machine code instruction on 'stdout'
-       c:   instructions machine code
-
-*******************************************************************************/
-
-u1 *intrp_disassinstr(u1 *code)
-{
-       FILE *savedout;
-       u1   *r;
-
-       savedout = vm_out;
-       vm_out = stdout;
-       r = (u1 *) vm_disassemble_inst((Inst *) code, vm_prim);
-       vm_out = savedout;
-
-       return r;
-}
-
-
-/* function disassemble ********************************************************
-
-       outputs a disassembler listing of some machine code on 'stdout'
-       code: pointer to first instruction
-       len:  code size (number of instructions * 4)
-
-*******************************************************************************/
-
-void intrp_disassemble(u1 *start, u1 *end)
-{
-       FILE *savedout;
-
-       printf("  --- disassembler listing ---\n");
-       savedout = vm_out;
-       vm_out = stdout;
-       vm_disassemble((Inst *) start, (Inst *) end, vm_prim);
-       vm_out = savedout;
-}
-
-
-void printarg_ui      (u4                 ui      )
-{
-       fprintf(vm_out, "%ud", ui);
-}
-
-void printarg_v       (Cell               v       )
-{
-       fprintf(vm_out, "%lld", (long long)v);
-}
-
-void printarg_Cell    (Cell               x       )
-{
-       fprintf(vm_out, "%lld", (long long)x);
-}
-
-
-void printarg_b       (s4                 b       )
-{
-       fprintf(vm_out, "%d", b);
-}
-
-void printarg_s       (s4                 s       )
-{
-       fprintf(vm_out, "%d", s);
-}
-
-void printarg_i       (s4                 i       )
-{
-       fprintf(vm_out, "%d", i);
-}
-
-void printarg_l       (s8                 l       )
-{
-       fprintf(vm_out, "%lld", (long long)l);
-}
-
-void printarg_f       (float              f       )
-{
-       fprintf(vm_out, "%f", (double)f);
-}
-
-void printarg_d       (double             d       )
-{
-       fprintf(vm_out, "%f", d);
-}
-
-void printarg_aRef    (java_objectheader *aRef    )
-{
-       fprintf(vm_out, "obj: %p", (void *)aRef);
-}
-
-void printarg_aArray  (java_arrayheader * aArray  )
-{
-       fprintf(vm_out, "array %p", (void *)aArray);
-}
-
-void printarg_aaTarget(Inst **            aaTarget)
-{
-       if (aaTarget) {
-               methodinfo *m=((methodinfo **)aaTarget)[3];
-               printarg_am(m);
-       } else
-               fprintf(vm_out, "NULL");
-}
-
-void printarg_aClass  (classinfo *        aClass  )
-{
-       if (aClass)
-               utf_fprint_printable_ascii_classname(vm_out, aClass->name);
-       else
-               fprintf(vm_out, "NULL");
-}
-
-void printarg_acr     (constant_classref *acr     )
-{
-       fprintf(vm_out, "cr: %p", (void *)acr);
-}
-
-void printarg_addr    (u1 *               addr    )
-{
-       fprintf(vm_out, "%p", (void *)addr);
-}
-
-void printarg_af      (functionptr        af      )
-{
-       fprintf(vm_out, "f: %p", (void *)af);
-}
-
-void printarg_afi     (fieldinfo *        afi      )
-{
-       if (afi) {
-               utf_fprint_printable_ascii_classname(vm_out, afi->clazz->name);
-               fprintf(vm_out, ".");
-               utf_fprint_printable_ascii(vm_out, afi->name);
-               utf_fprint_printable_ascii(vm_out, afi->descriptor);
-       } else
-               fprintf(vm_out, "fi=NULL");
-}
-
-void printarg_am      (methodinfo *       am      )
-{
-       if (am) {
-               utf_fprint_printable_ascii_classname(vm_out, am->clazz->name);
-               fprintf(vm_out, ".");
-               utf_fprint_printable_ascii(vm_out, am->name);
-               utf_fprint_printable_ascii(vm_out, am->descriptor);
-       } else
-               fprintf(vm_out, "m=NULL");
-}
-
-void printarg_acell   (Cell *             acell   )
-{
-       fprintf(vm_out, "%p", (void *)acell);
-}
-
-void printarg_ainst   (Inst *             ainst   )
-{
-       fprintf(vm_out, "%p", (void *)ainst);
-}
-
-void printarg_auf     (unresolved_field * auf     )
-{
-       if (auf) {
-               utf_fprint_printable_ascii(vm_out, auf->fieldref->name);
-               fprintf(vm_out, " (type ");
-               utf_fprint_printable_ascii(vm_out, auf->fieldref->descriptor);
-               fprintf(vm_out, ")");
-       } else
-               fprintf(vm_out, "NULL");
-}
-
-void printarg_aum     (unresolved_method *aum     )
-{
-       if (aum) {
-               utf_fprint_printable_ascii_classname(vm_out, METHODREF_CLASSNAME(aum->methodref));
-               fprintf(vm_out, ".");
-               utf_fprint_printable_ascii(vm_out, aum->methodref->name);
-               utf_fprint_printable_ascii(vm_out, aum->methodref->descriptor);
-       } else
-               fprintf(vm_out, "NULL");
-}
-
-void printarg_avftbl  (vftbl_t *          avftbl  )
-{
-       if (avftbl) {
-               fprintf(vm_out, "vftbl: ");
-               utf_fprint_printable_ascii_classname(vm_out, avftbl->class->name);
-       } else
-               fprintf(vm_out, "NULL");
-}
-
-
-/*
- * 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/jit/intrp/disass.cpp b/src/vm/jit/intrp/disass.cpp
new file mode 100644 (file)
index 0000000..f2b74ef
--- /dev/null
@@ -0,0 +1,240 @@
+/* src/vm/jit/intrp/disass.c - disassembler wrapper for interpreter
+
+   Copyright (C) 1996-2005, 2006, 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 <stdio.h>
+
+#include "vm/types.h"
+
+#include "vm/jit/intrp/intrp.h"
+
+
+/* function disassinstr ********************************************************
+
+       outputs a disassembler listing of one machine code instruction on 'stdout'
+       c:   instructions machine code
+
+*******************************************************************************/
+
+u1 *intrp_disassinstr(u1 *code)
+{
+       FILE *savedout;
+       u1   *r;
+
+       savedout = vm_out;
+       vm_out = stdout;
+       r = (u1 *) vm_disassemble_inst((Inst *) code, vm_prim);
+       vm_out = savedout;
+
+       return r;
+}
+
+
+/* function disassemble ********************************************************
+
+       outputs a disassembler listing of some machine code on 'stdout'
+       code: pointer to first instruction
+       len:  code size (number of instructions * 4)
+
+*******************************************************************************/
+
+void intrp_disassemble(u1 *start, u1 *end)
+{
+       FILE *savedout;
+
+       printf("  --- disassembler listing ---\n");
+       savedout = vm_out;
+       vm_out = stdout;
+       vm_disassemble((Inst *) start, (Inst *) end, vm_prim);
+       vm_out = savedout;
+}
+
+
+void printarg_ui      (u4                 ui      )
+{
+       fprintf(vm_out, "%ud", ui);
+}
+
+void printarg_v       (Cell               v       )
+{
+       fprintf(vm_out, "%lld", (long long)v);
+}
+
+void printarg_Cell    (Cell               x       )
+{
+       fprintf(vm_out, "%lld", (long long)x);
+}
+
+
+void printarg_b       (s4                 b       )
+{
+       fprintf(vm_out, "%d", b);
+}
+
+void printarg_s       (s4                 s       )
+{
+       fprintf(vm_out, "%d", s);
+}
+
+void printarg_i       (s4                 i       )
+{
+       fprintf(vm_out, "%d", i);
+}
+
+void printarg_l       (s8                 l       )
+{
+       fprintf(vm_out, "%lld", (long long)l);
+}
+
+void printarg_f       (float              f       )
+{
+       fprintf(vm_out, "%f", (double)f);
+}
+
+void printarg_d       (double             d       )
+{
+       fprintf(vm_out, "%f", d);
+}
+
+void printarg_aRef    (java_objectheader *aRef    )
+{
+       fprintf(vm_out, "obj: %p", (void *)aRef);
+}
+
+void printarg_aArray  (java_arrayheader * aArray  )
+{
+       fprintf(vm_out, "array %p", (void *)aArray);
+}
+
+void printarg_aaTarget(Inst **            aaTarget)
+{
+       if (aaTarget) {
+               methodinfo *m=((methodinfo **)aaTarget)[3];
+               printarg_am(m);
+       } else
+               fprintf(vm_out, "NULL");
+}
+
+void printarg_aClass  (classinfo *        aClass  )
+{
+       if (aClass)
+               utf_fprint_printable_ascii_classname(vm_out, aClass->name);
+       else
+               fprintf(vm_out, "NULL");
+}
+
+void printarg_acr     (constant_classref *acr     )
+{
+       fprintf(vm_out, "cr: %p", (void *)acr);
+}
+
+void printarg_addr    (u1 *               addr    )
+{
+       fprintf(vm_out, "%p", (void *)addr);
+}
+
+void printarg_af      (functionptr        af      )
+{
+       fprintf(vm_out, "f: %p", (void *)af);
+}
+
+void printarg_afi     (fieldinfo *        afi      )
+{
+       if (afi) {
+               utf_fprint_printable_ascii_classname(vm_out, afi->clazz->name);
+               fprintf(vm_out, ".");
+               utf_fprint_printable_ascii(vm_out, afi->name);
+               utf_fprint_printable_ascii(vm_out, afi->descriptor);
+       } else
+               fprintf(vm_out, "fi=NULL");
+}
+
+void printarg_am      (methodinfo *       am      )
+{
+       if (am) {
+               utf_fprint_printable_ascii_classname(vm_out, am->clazz->name);
+               fprintf(vm_out, ".");
+               utf_fprint_printable_ascii(vm_out, am->name);
+               utf_fprint_printable_ascii(vm_out, am->descriptor);
+       } else
+               fprintf(vm_out, "m=NULL");
+}
+
+void printarg_acell   (Cell *             acell   )
+{
+       fprintf(vm_out, "%p", (void *)acell);
+}
+
+void printarg_ainst   (Inst *             ainst   )
+{
+       fprintf(vm_out, "%p", (void *)ainst);
+}
+
+void printarg_auf     (unresolved_field * auf     )
+{
+       if (auf) {
+               utf_fprint_printable_ascii(vm_out, auf->fieldref->name);
+               fprintf(vm_out, " (type ");
+               utf_fprint_printable_ascii(vm_out, auf->fieldref->descriptor);
+               fprintf(vm_out, ")");
+       } else
+               fprintf(vm_out, "NULL");
+}
+
+void printarg_aum     (unresolved_method *aum     )
+{
+       if (aum) {
+               utf_fprint_printable_ascii_classname(vm_out, METHODREF_CLASSNAME(aum->methodref));
+               fprintf(vm_out, ".");
+               utf_fprint_printable_ascii(vm_out, aum->methodref->name);
+               utf_fprint_printable_ascii(vm_out, aum->methodref->descriptor);
+       } else
+               fprintf(vm_out, "NULL");
+}
+
+void printarg_avftbl  (vftbl_t *          avftbl  )
+{
+       if (avftbl) {
+               fprintf(vm_out, "vftbl: ");
+               utf_fprint_printable_ascii_classname(vm_out, avftbl->class->name);
+       } else
+               fprintf(vm_out, "NULL");
+}
+
+
+/*
+ * 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 03073954cc44247fa5120a284358b4abb0eece89..6b3b60e400fcf478545cca2ba74748b525884c28 100644 (file)
@@ -46,8 +46,8 @@ typedef s4 Cell;
 
 #include "vm/class.hpp"
 #include "vm/global.h"
-#include "vm/linker.h"
-#include "vm/method.h"
+#include "vm/linker.hpp"
+#include "vm/method.hpp"
 #include "vm/references.h"
 #include "vm/resolve.hpp"
 
index 9be1a6fdf57352a18aebed489cafab28132f1169..027ff15021a2870310213db23eb57242bb380992 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <stdint.h>
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 
 #include "vm/jit/ir/instruction.hpp"
 
index c9f3e30753d9d6c2478a30467e95ca3f7fe30608..cfbaead66282590a3cfca3300b19b61f70231cae 100644 (file)
@@ -35,7 +35,7 @@ typedef struct insinfo_inline insinfo_inline;
 
 #include <stdint.h>
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 
 #include "vm/jit/jit.hpp"
 #include "vm/jit/replace.hpp"
index 095e9840155dba245ac7ec97a0a07909feaa1efb..baaf5900f62eeedcb16ce7aee9dbaa6e9ce91ac1 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"
@@ -58,7 +58,7 @@
 #include "vm/jit/disass.h"
 #include "vm/jit/dseg.h"
 #include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/reg.h"
 
 #include "vm/jit/show.hpp"
@@ -80,7 +80,7 @@
 #endif
 
 #if defined(ENABLE_INLINING)
-# include "vm/jit/inline/inline.h"
+# include "vm/jit/inline/inline.hpp"
 #endif
 
 #include "vm/jit/ir/bytecode.h"
@@ -99,7 +99,7 @@
 # include "vm/jit/python.h"
 #endif
 
-#include "vm/jit/verify/typecheck.h"
+#include "vm/jit/verify/typecheck.hpp"
 
 
 /* debug macros ***************************************************************/
index 4a235519fb49e01bb1acb3b44ef847bee6ef98b0..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"
 
@@ -52,7 +52,7 @@ typedef struct exception_entry exception_entry;
 #include "vm/jit/stacktrace.hpp"
 
 #if defined(ENABLE_INLINING)
-# include "vm/jit/inline/inline.h"
+# include "vm/jit/inline/inline.hpp"
 #endif
 
 #include "vm/jit/ir/bytecode.h"
@@ -68,7 +68,7 @@ typedef struct exception_entry exception_entry;
 # include "vm/jit/allocator/lsra.h"
 #endif
 
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
 
 
 /* common jit/codegen macros **************************************************/
index 620cc1a3112b0cb1e3d9661d85c3d52262343d5b..1fa5440ea25cc627266a5c847beaa1c43a7cc7f2 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 6a0254b8c89e7f218e69e8ae4948f85521475f09..a6ad45abeef0244cfe0ed521ba3f4dd8acdce5fb 100644 (file)
@@ -57,7 +57,7 @@
 #include "vm/jit/emit-common.hpp"
 #include "vm/jit/jit.hpp"
 #include "vm/jit/abi.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/reg.h"
 #include "vm/jit/replace.hpp"
 #include "vm/jit/stacktrace.hpp"
index ee88ea3b528dc83eab73cb310fa788b17a3c773c..e81137a706df83df1b9f9581ae93a76d7d8efd1a 100644 (file)
@@ -1403,13 +1403,13 @@ bool codegen_emit(jitdata *jd)
                        M_CMPLT(s1, s2, REG_ITMP3);
                        M_CMPLT(s2, s1, REG_ITMP1);
                        M_ISUB(REG_ITMP1, REG_ITMP3, d);
-                       M_BNEZ(d, 4);
-                       M_NOP;
+                       emit_label_bnez(cd, BRANCH_LABEL_1, d);
                        s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
                        s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
                        M_CMPULT(s1, s2, REG_ITMP3);
                        M_CMPULT(s2, s1, REG_ITMP1);
                        M_ISUB(REG_ITMP1, REG_ITMP3, d);
+                       emit_label(cd, BRANCH_LABEL_1);
 #endif
                        emit_store_dst(jd, iptr, d);
                        break;
@@ -2430,12 +2430,12 @@ bool codegen_emit(jitdata *jd)
                                ICONST(REG_ITMP2, iptr->sx.val.l >> 32);
                                M_CMPLT(s1, REG_ITMP2, REG_ITMP3);
                                emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+                               emit_label_bne(cd, BRANCH_LABEL_1, s1, REG_ITMP2);
                                s2 = emit_load_s1_low(jd, iptr, REG_ITMP3);
-                               M_BNE(s1, REG_ITMP2, 5); /* XXX */
-                               M_NOP;
                                ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
                                M_CMPULT(s2, REG_ITMP2, REG_ITMP3);
                                emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+                               emit_label(cd, BRANCH_LABEL_1);
                        }
 #endif
                        break;
@@ -2460,22 +2460,22 @@ bool codegen_emit(jitdata *jd)
 #else
                        if (iptr->sx.val.l == 0) {
                                s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED);
-                               M_BGTZ(GET_HIGH_REG(s1), 5); /* XXX */
-                               M_NOP;
+                               emit_label_bgtz(cd, BRANCH_LABEL_1, GET_HIGH_REG(s1));
                                emit_bltz(cd, iptr->dst.block, GET_HIGH_REG(s1));
-                               emit_beqz(cd, iptr->dst.block, GET_LOW_REG(s1));
+                               emit_beqz(cd, iptr->dst.block, GET_LOW_REG(s1));        
+                               emit_label(cd, BRANCH_LABEL_1);
                        }
                        else {
                                s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
                                ICONST(REG_ITMP2, iptr->sx.val.l >> 32);
                                M_CMPLT(s1, REG_ITMP2, REG_ITMP3);
                                emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+                               emit_label_bne(cd, BRANCH_LABEL_1, s1, REG_ITMP2);
                                s2 = emit_load_s1_low(jd, iptr, REG_ITMP3);
-                               M_BNE(s1, REG_ITMP2, 5); /* XXX */
-                               M_NOP;
                                ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
                                M_CMPUGT(s2, REG_ITMP2, REG_ITMP3);
                                emit_beqz(cd, iptr->dst.block, REG_ITMP3);
+                               emit_label(cd, BRANCH_LABEL_1);
                        }
 #endif
                        break;
@@ -2530,21 +2530,21 @@ bool codegen_emit(jitdata *jd)
                        if (iptr->sx.val.l == 0) {
                                s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED);
                                emit_bgtz(cd, iptr->dst.block, GET_HIGH_REG(s1));
-                               M_BLTZ(GET_HIGH_REG(s1), 3); /* XXX */
-                               M_NOP;
+                               emit_label_bltz(cd, BRANCH_LABEL_1, GET_HIGH_REG(s1));
                                emit_bnez(cd, iptr->dst.block, GET_LOW_REG(s1));
+                               emit_label(cd, BRANCH_LABEL_1);
                        }
                        else {
                                s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
                                ICONST(REG_ITMP2, iptr->sx.val.l >> 32);
                                M_CMPGT(s1, REG_ITMP2, REG_ITMP3);
                                emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+                               emit_label_bne(cd, BRANCH_LABEL_1, s1, REG_ITMP2);
                                s2 = emit_load_s1_low(jd, iptr, REG_ITMP3);
-                               M_BNE(s1, REG_ITMP2, 5); /* XXX */
-                               M_NOP;
                                ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
                                M_CMPUGT(s2, REG_ITMP2, REG_ITMP3);
                                emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+                               emit_label(cd, BRANCH_LABEL_1);
                        }
 #endif
                        break;
@@ -2576,12 +2576,12 @@ bool codegen_emit(jitdata *jd)
                                ICONST(REG_ITMP2, iptr->sx.val.l >> 32);
                                M_CMPGT(s1, REG_ITMP2, REG_ITMP3);
                                emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+                               emit_label_bne(cd, BRANCH_LABEL_1, s1, REG_ITMP2);
                                s2 = emit_load_s1_low(jd, iptr, REG_ITMP3);
-                               M_BNE(s1, REG_ITMP2, 5); /* XXX */
-                               M_NOP;
                                ICONST(REG_ITMP2, iptr->sx.val.l & 0xffffffff);
                                M_CMPULT(s2, REG_ITMP2, REG_ITMP3);
                                emit_beqz(cd, iptr->dst.block, REG_ITMP3);
+                               emit_label(cd, BRANCH_LABEL_1);
                        }
 #endif
                        break;
@@ -2603,11 +2603,11 @@ bool codegen_emit(jitdata *jd)
 
                        s1 = emit_load_s1_high(jd, iptr, REG_ITMP1);
                        s2 = emit_load_s2_high(jd, iptr, REG_ITMP2);
-                       M_BNE(s1, s2, 3); /* XXX TWISTI: uff, that is a problem */
-                       M_NOP;
+                       emit_label_bne(cd, BRANCH_LABEL_1, s1, s2);
                        s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
                        s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
                        emit_beq(cd, iptr->dst.block, s1, s2);
+                       emit_label(cd, BRANCH_LABEL_1);
                        break;
 #endif
 
@@ -2654,13 +2654,12 @@ bool codegen_emit(jitdata *jd)
                        M_CMPLT(s1, s2, REG_ITMP3);
                        emit_bnez(cd, iptr->dst.block, REG_ITMP3);
                        M_CMPGT(s1, s2, REG_ITMP3);
-                       /* load low-bits before the branch, so we know the distance */
+                       emit_label_bnez(cd, BRANCH_LABEL_1, REG_ITMP3);
                        s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
                        s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
-                       M_BNEZ(REG_ITMP3, 4); /* XXX */
-                       M_NOP;
                        M_CMPULT(s1, s2, REG_ITMP3);
                        emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+                       emit_label(cd, BRANCH_LABEL_1);
                        break;
 #endif
 
@@ -2683,13 +2682,12 @@ bool codegen_emit(jitdata *jd)
                        M_CMPGT(s1, s2, REG_ITMP3);
                        emit_bnez(cd, iptr->dst.block, REG_ITMP3);
                        M_CMPLT(s1, s2, REG_ITMP3);
-                       /* load low-bits before the branch, so we know the distance */
+                       emit_label_bnez(cd, BRANCH_LABEL_1, REG_ITMP3);
                        s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
                        s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
-                       M_BNEZ(REG_ITMP3, 4); /* XXX */
-                       M_NOP;
                        M_CMPUGT(s1, s2, REG_ITMP3);
                        emit_bnez(cd, iptr->dst.block, REG_ITMP3);
+                       emit_label(cd, BRANCH_LABEL_1);
                        break;
 #endif
 
@@ -2712,13 +2710,12 @@ bool codegen_emit(jitdata *jd)
                        M_CMPLT(s1, s2, REG_ITMP3);
                        emit_bnez(cd, iptr->dst.block, REG_ITMP3);
                        M_CMPGT(s1, s2, REG_ITMP3);
-                       /* load low-bits before the branch, so we know the distance */
+                       emit_label_bnez(cd, BRANCH_LABEL_1, REG_ITMP3);
                        s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
                        s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
-                       M_BNEZ(REG_ITMP3, 4); /* XXX */
-                       M_NOP;
                        M_CMPUGT(s1, s2, REG_ITMP3);
                        emit_beqz(cd, iptr->dst.block, REG_ITMP3);
+                       emit_label(cd, BRANCH_LABEL_1);
                        break;
 #endif
 
@@ -2741,13 +2738,12 @@ bool codegen_emit(jitdata *jd)
                        M_CMPGT(s1, s2, REG_ITMP3);
                        emit_bnez(cd, iptr->dst.block, REG_ITMP3);
                        M_CMPLT(s1, s2, REG_ITMP3);
-                       /* load low-bits before the branch, so we know the distance */
+                       emit_label_bnez(cd, BRANCH_LABEL_1, REG_ITMP3);
                        s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
                        s2 = emit_load_s2_low(jd, iptr, REG_ITMP2);
-                       M_BNEZ(REG_ITMP3, 4); /* XXX */
-                       M_NOP;
                        M_CMPULT(s1, s2, REG_ITMP3);
                        emit_beqz(cd, iptr->dst.block, REG_ITMP3);
+                       emit_label(cd, BRANCH_LABEL_1);
                        break;
 #endif
 
index a2d9157c6868bdba6fde3e4423fd73ed9bdc46b9..663aa91f7cb711965a36e4d613b0da09d7717e3b 100644 (file)
@@ -34,9 +34,9 @@
 
 #include "mm/memory.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #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 2d7044bc65b3ef3acfb74f60638e876275658180..444503fa7d03505b50b74c156bc74668a14933ad 100644 (file)
@@ -33,7 +33,7 @@
 #include "toolbox/bitvector.h"
 
 #include "vm/class.hpp"
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 #include "vm/references.h"
 #include "vm/resolve.hpp"
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
diff --git a/src/vm/jit/parse.c b/src/vm/jit/parse.c
deleted file mode 100644 (file)
index 7b1c1ac..0000000
+++ /dev/null
@@ -1,1922 +0,0 @@
-/* src/vm/jit/parse.c - parser for JavaVM to intermediate code translation
-
-   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 <string.h>
-
-#include "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "native/native.hpp"
-
-#include "threads/lock.hpp"
-
-#include "toolbox/logging.h"
-
-#include "vm/jit/builtin.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/global.h"
-#include "vm/linker.h"
-#include "vm/loader.hpp"
-#include "vm/options.h"
-#include "vm/resolve.hpp"
-
-#if defined(ENABLE_STATISTICS)
-# include "vm/statistics.h"
-#endif
-
-#include "vm/string.hpp"
-#include "vm/suck.hpp"
-
-#include "vm/jit/asmpart.h"
-#include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
-#include "vm/jit/loop/loop.h"
-
-#include "vm/jit/ir/bytecode.h"
-
-
-#define INSTRUCTIONS_INCREMENT  5  /* number of additional instructions to    */
-                                   /* allocate if space runs out              */
-
-
-/* local macros ***************************************************************/
-
-#define BYTECODEINDEX_TO_BASICBLOCK(dst) \
-    do { \
-        (dst).block = \
-            parse_bytecodeindex_to_basicblock(jd, &pd, (dst).insindex); \
-    } while (0)
-
-
-/* parserdata_t ***************************************************************/
-
-typedef struct parsedata_t parsedata_t;
-
-struct parsedata_t {
-       u1          *bytecodestart;         /* start of bytecode instructions     */
-       u1          *basicblockstart;       /* start of bytecode basic-blocks     */
-
-       s4          *bytecodemap;           /* bytecode to IR mapping             */
-       
-       instruction *instructions;          /* instruction array                  */
-       s4           instructionslength;    /* length of the instruction array    */
-
-       s4          *instructionmap;        /* IR to basic-block mapping          */
-};
-
-
-/* parse_setup *****************************************************************
-
-   Fills the passed parsedata_t structure.
-
-*******************************************************************************/
-
-static void parse_setup(jitdata *jd, parsedata_t *pd)
-{
-       methodinfo *m;
-
-       /* get required compiler data */
-
-       m = jd->m;
-
-       /* bytecode start array */
-
-       pd->bytecodestart = DMNEW(u1, m->jcodelength + 1);
-       MZERO(pd->bytecodestart, u1, m->jcodelength + 1);
-
-       /* bytecode basic-block start array */
-
-       pd->basicblockstart = DMNEW(u1, m->jcodelength + 1);
-       MZERO(pd->basicblockstart, u1, m->jcodelength + 1);
-
-       /* bytecode instruction index to IR instruction mapping */
-
-       pd->bytecodemap = DMNEW(s4, m->jcodelength + 1);
-       MSET(pd->bytecodemap, -1, s4, m->jcodelength + 1);
-
-       /* allocate the instruction array */
-
-       pd->instructionslength = m->jcodelength + 1;
-       pd->instructions = DMNEW(instruction, pd->instructionslength);
-
-       /* Zero the intermediate instructions array so we don't have any
-          invalid pointers in it if we cannot finish stack_analyse(). */
-
-       MZERO(pd->instructions, instruction, pd->instructionslength);
-
-       /* The instructionmap is allocated later when we know the count of
-          instructions. */
-
-       pd->instructionmap = NULL;
-}
-
-
-/* parse_realloc_instructions **************************************************
-
-   Reallocate the instructions array so there is room for at least N 
-   additional instructions.
-
-   RETURN VALUE:
-       the new value for iptr
-
-*******************************************************************************/
-
-static instruction *parse_realloc_instructions(parsedata_t *pd, s4 icount, s4 n)
-{
-       /* increase the size of the instruction array */
-
-       pd->instructionslength += (n + INSTRUCTIONS_INCREMENT);
-
-       /* reallocate the array */
-
-       pd->instructions = DMREALLOC(pd->instructions, instruction, icount,
-                                                                pd->instructionslength);
-       MZERO(pd->instructions + icount, instruction,
-                 (pd->instructionslength - icount));
-
-       /* return the iptr */
-
-       return pd->instructions + icount;
-}
-
-
-/* parse_bytecodeindex_to_basicblock *******************************************
-
-   Resolves a bytecode index to the corresponding basic block.
-
-*******************************************************************************/
-
-static basicblock *parse_bytecodeindex_to_basicblock(jitdata *jd,
-                                                                                                        parsedata_t *pd,
-                                                                                                        s4 bcindex)
-{
-       s4          irindex;
-       basicblock *bb;
-
-       irindex = pd->bytecodemap[bcindex];
-       bb      = jd->basicblocks + pd->instructionmap[irindex];
-
-       return bb;
-}
-
-
-/* parse_mark_exception_boundaries *********************************************
-
-   Mark exception handlers and the boundaries of the handled regions as
-   basic block boundaries.
-
-   IN:
-       jd...............current jitdata
-
-   RETURN VALUE:
-       true.............everything ok
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-static bool parse_mark_exception_boundaries(jitdata *jd, parsedata_t *pd)
-{
-       s4                   bcindex;
-       s4                   i;
-       s4                   len;
-       raw_exception_entry *rex;
-       methodinfo          *m;
-
-       m = jd->m;
-       
-       len = m->rawexceptiontablelength;
-
-       if (len == 0)
-               return true;
-
-       rex = m->rawexceptiontable;
-
-       for (i = 0; i < len; ++i, ++rex) {
-
-               /* the start of the handled region becomes a basic block start */
-
-               bcindex = rex->startpc;
-               CHECK_BYTECODE_INDEX(bcindex);
-               MARK_BASICBLOCK(pd, bcindex);
-               
-               bcindex = rex->endpc; /* see JVM Spec 4.7.3 */
-               CHECK_BYTECODE_INDEX_EXCLUSIVE(bcindex);
-
-               /* check that the range is valid */
-
-#if defined(ENABLE_VERIFIER)
-               if (bcindex <= rex->startpc) {
-                       exceptions_throw_verifyerror(m, "Invalid exception handler range");
-                       return false;
-               }
-#endif
-               
-               /* End of handled region becomes a basic block boundary (if it
-                  is the bytecode end, we'll use the special end block that
-                  is created anyway). */
-
-               if (bcindex < m->jcodelength)
-                       MARK_BASICBLOCK(pd, bcindex);
-               else
-                       jd->branchtoend = true;
-
-               /* the start of the handler becomes a basic block start  */
-
-               bcindex = rex->handlerpc;
-               CHECK_BYTECODE_INDEX(bcindex);
-               MARK_BASICBLOCK(pd, bcindex);
-       }
-
-       /* everything ok */
-
-       return true;
-
-#if defined(ENABLE_VERIFIER)
-throw_invalid_bytecode_index:
-       exceptions_throw_verifyerror(m,
-                                                                "Illegal bytecode index in exception table");
-       return false;
-#endif
-}
-
-
-/* parse_resolve_exception_table ***********************************************
-
-   Enter the exception handlers and their ranges, resolved to basicblock *s,
-   in the jitdata.
-
-   IN:
-       jd...............current jitdata
-
-   RETURN VALUE:
-          true.............everything ok
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-static bool parse_resolve_exception_table(jitdata *jd, parsedata_t *pd)
-{
-       methodinfo          *m;
-       raw_exception_entry *rex;
-       exception_entry     *ex;
-       s4                   i;
-       s4                   len;
-       classinfo           *exclass;
-
-       m = jd->m;
-
-       len = m->rawexceptiontablelength;
-
-       /* common case: no handler entries */
-
-       if (len == 0)
-               return true;
-
-       /* allocate the exception table */
-
-       jd->exceptiontablelength = len;
-       jd->exceptiontable = DMNEW(exception_entry, len + 1); /* XXX why +1? */
-
-       /* copy and resolve the entries */
-
-       ex = jd->exceptiontable;
-       rex = m->rawexceptiontable;
-
-       for (i = 0; i < len; ++i, ++rex, ++ex) {
-               /* resolve instruction indices to basic blocks */
-
-               ex->start   = parse_bytecodeindex_to_basicblock(jd, pd, rex->startpc);
-               ex->end     = parse_bytecodeindex_to_basicblock(jd, pd, rex->endpc);
-               ex->handler = parse_bytecodeindex_to_basicblock(jd, pd, rex->handlerpc);
-
-               /* lazily resolve the catchtype */
-
-               if (rex->catchtype.any != NULL) {
-                       if (!resolve_classref_or_classinfo(m,
-                                                                                          rex->catchtype,
-                                                                                          resolveLazy, true, false,
-                                                                                          &exclass))
-                               return false;
-
-                       /* if resolved, enter the result of resolution in the table */
-
-                       if (exclass != NULL)
-                               rex->catchtype.cls = exclass;
-               }
-
-               ex->catchtype = rex->catchtype;
-               ex->next = NULL;   /* set by loop analysis */
-               ex->down = ex + 1; /* link to next exception entry */
-       }
-
-       /* terminate the ->down linked list */
-
-       assert(ex != jd->exceptiontable);
-       ex[-1].down = NULL;
-
-       return true;
-}
-
-
-/*******************************************************************************
-
-       function 'parse' scans the JavaVM code and generates intermediate code
-
-       During parsing the block index table is used to store at bit pos 0
-       a flag which marks basic block starts and at position 1 to 31 the
-       intermediate instruction index. After parsing the block index table
-       is scanned, for marked positions a block is generated and the block
-       number is stored in the block index table.
-
-*******************************************************************************/
-
-/*** macro for checking the length of the bytecode ***/
-
-#if defined(ENABLE_VERIFIER)
-#define CHECK_END_OF_BYTECODE(neededlength) \
-       do { \
-               if ((neededlength) > m->jcodelength) \
-                       goto throw_unexpected_end_of_bytecode; \
-       } while (0)
-#else /* !ENABLE_VERIFIER */
-#define CHECK_END_OF_BYTECODE(neededlength)
-#endif /* ENABLE_VERIFIER */
-
-bool parse(jitdata *jd)
-{
-       methodinfo  *m;                     /* method being parsed                */
-       codeinfo    *code;
-       parsedata_t  pd;
-       instruction *iptr;                  /* current ptr into instruction array */
-
-       s4           bcindex;               /* bytecode instruction index         */
-       s4           nextbc;                /* start of next bytecode instruction */
-       s4           opcode;                /* bytecode instruction opcode        */
-
-       s4           irindex;               /* IR instruction index               */
-       s4           ircount;               /* IR instruction count               */
-
-       s4           bbcount;               /* basic block count                  */
-
-       int  s_count = 0;             /* stack element counter                    */
-       bool blockend;                /* true if basic block end has been reached */
-       bool iswide;                  /* true if last instruction was a wide      */
-
-       constant_classref  *cr;
-       constant_classref  *compr;
-       classinfo          *c;
-       builtintable_entry *bte;
-       constant_FMIref    *fmi;
-       methoddesc         *md;
-       unresolved_method  *um;
-       unresolved_field   *uf;
-
-       resolve_result_t    result;
-       u2                  lineindex = 0;
-       u2                  currentline = 0;
-       u2                  linepcchange = 0;
-       u4                  flags;
-       basicblock         *bptr;
-
-       int                *local_map; /* local pointer to renaming map           */
-                                      /* is assigned to rd->local_map at the end */
-       branch_target_t *table;
-       lookup_target_t *lookup;
-       s4               i;
-       s4               j;
-
-       /* get required compiler data */
-
-       m    = jd->m;
-       code = jd->code;
-
-       /* allocate buffers for local variable renaming */
-
-       local_map = DMNEW(int, m->maxlocals * 5);
-
-       for (i = 0; i < m->maxlocals; i++) {
-               local_map[i * 5 + 0] = 0;
-               local_map[i * 5 + 1] = 0;
-               local_map[i * 5 + 2] = 0;
-               local_map[i * 5 + 3] = 0;
-               local_map[i * 5 + 4] = 0;
-       }
-
-       /* initialize the parse data structures */
-  
-       parse_setup(jd, &pd);
-  
-       /* initialize local variables */
-  
-       iptr     = pd.instructions;
-       ircount  = 0;
-       bbcount  = 0;
-       blockend = false;
-       iswide   = false;
-
-       /* mark basic block boundaries for exception table */
-
-       if (!parse_mark_exception_boundaries(jd, &pd))
-               return false;
-
-       /* initialize stack element counter */
-
-       s_count = 1 + m->rawexceptiontablelength;
-
-       /* setup line number info */
-
-       currentline = 0;
-       linepcchange = 0;
-
-       if (m->linenumbercount == 0) {
-               lineindex = 0;
-       }
-       else {
-               linepcchange = m->linenumbers[0].start_pc;
-       }
-
-       /*** LOOP OVER ALL BYTECODE INSTRUCTIONS **********************************/
-
-       for (bcindex = 0; bcindex < m->jcodelength; bcindex = nextbc) {
-
-               /* mark this position as a valid bytecode instruction start */
-
-               pd.bytecodestart[bcindex] = 1;
-
-               /* change the current line number, if necessary */
-
-               /* XXX rewrite this using pointer arithmetic */
-
-               if (linepcchange == bcindex) {
-                       if (m->linenumbercount > lineindex) {
-next_linenumber:
-                               currentline = m->linenumbers[lineindex].line_number;
-                               lineindex++;
-                               if (lineindex < m->linenumbercount) {
-                                       linepcchange = m->linenumbers[lineindex].start_pc;
-                                       if (linepcchange == bcindex)
-                                               goto next_linenumber;
-                               }
-                       }
-               }
-
-fetch_opcode:
-               /* fetch next opcode  */        
-
-               opcode = SUCK_BE_U1(m->jcode + bcindex);
-
-               /* If the previous instruction was a block-end instruction,
-                  mark the current bytecode instruction as basic-block
-                  starting instruction. */
-
-               /* NOTE: Some compilers put a BC_nop after a blockend
-                  instruction. */
-
-               if (blockend && (opcode != BC_nop)) {
-                       MARK_BASICBLOCK(&pd, bcindex);
-                       blockend = false;
-               }
-
-               /* If the current bytecode instruction was marked as
-                  basic-block starting instruction before (e.g. blockend,
-                  forward-branch target), mark the current IR instruction
-                  too. */
-
-               if (pd.basicblockstart[bcindex] != 0) {
-                       /* We need a NOP as last instruction in each basic block
-                          for basic block reordering (may be replaced with a GOTO
-                          later). */
-
-                       INSTRUCTIONS_CHECK(1);
-                       OP(ICMD_NOP);
-               }
-
-               /* store intermediate instruction count (bit 0 mark block starts) */
-
-               pd.bytecodemap[bcindex] = ircount;
-
-               /* compute next instruction start */
-
-               nextbc = bcindex + bytecode[opcode].length;
-
-               CHECK_END_OF_BYTECODE(nextbc);
-
-               /* add stack elements produced by this instruction */
-
-               s_count += bytecode[opcode].slots;
-
-               /* We check here for the space of 1 instruction in the
-                  instruction array.  If an opcode is converted to more than
-                  1 instruction, this is checked in the corresponding
-                  case. */
-
-               INSTRUCTIONS_CHECK(1);
-
-               /* translate this bytecode instruction */
-               switch (opcode) {
-
-               case BC_nop:
-                       break;
-
-               /* pushing constants onto the stack ***********************************/
-
-               case BC_bipush:
-                       OP_LOADCONST_I(SUCK_BE_S1(m->jcode + bcindex + 1));
-                       break;
-
-               case BC_sipush:
-                       OP_LOADCONST_I(SUCK_BE_S2(m->jcode + bcindex + 1));
-                       break;
-
-               case BC_ldc1:
-                       i = SUCK_BE_U1(m->jcode + bcindex + 1);
-                       goto pushconstantitem;
-
-               case BC_ldc2:
-               case BC_ldc2w:
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-
-               pushconstantitem:
-
-#if defined(ENABLE_VERIFIER)
-                       if (i >= m->clazz->cpcount) {
-                               exceptions_throw_verifyerror(m,
-                                       "Attempt to access constant outside range");
-                               return false;
-                       }
-#endif
-
-                       switch (m->clazz->cptags[i]) {
-                       case CONSTANT_Integer:
-                               OP_LOADCONST_I(((constant_integer *) (m->clazz->cpinfos[i]))->value);
-                               break;
-                       case CONSTANT_Long:
-                               OP_LOADCONST_L(((constant_long *) (m->clazz->cpinfos[i]))->value);
-                               break;
-                       case CONSTANT_Float:
-                               OP_LOADCONST_F(((constant_float *) (m->clazz->cpinfos[i]))->value);
-                               break;
-                       case CONSTANT_Double:
-                               OP_LOADCONST_D(((constant_double *) (m->clazz->cpinfos[i]))->value);
-                               break;
-                       case CONSTANT_String:
-                               OP_LOADCONST_STRING(literalstring_new((utf *) (m->clazz->cpinfos[i])));
-                               break;
-                       case CONSTANT_Class:
-                               cr = (constant_classref *) (m->clazz->cpinfos[i]);
-
-                               if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
-                                       return false;
-
-                               /* if not resolved, c == NULL */
-
-                               OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr);
-
-                               break;
-
-#if defined(ENABLE_VERIFIER)
-                       default:
-                               exceptions_throw_verifyerror(m,
-                                               "Invalid constant type to push");
-                               return false;
-#endif
-                       }
-                       break;
-
-               case BC_aconst_null:
-                       OP_LOADCONST_NULL();
-                       break;
-
-               case BC_iconst_m1:
-               case BC_iconst_0:
-               case BC_iconst_1:
-               case BC_iconst_2:
-               case BC_iconst_3:
-               case BC_iconst_4:
-               case BC_iconst_5:
-                       OP_LOADCONST_I(opcode - BC_iconst_0);
-                       break;
-
-               case BC_lconst_0:
-               case BC_lconst_1:
-                       OP_LOADCONST_L(opcode - BC_lconst_0);
-                       break;
-
-               case BC_fconst_0:
-               case BC_fconst_1:
-               case BC_fconst_2:
-                       OP_LOADCONST_F(opcode - BC_fconst_0);
-                       break;
-
-               case BC_dconst_0:
-               case BC_dconst_1:
-                       OP_LOADCONST_D(opcode - BC_dconst_0);
-                       break;
-
-               /* stack operations ***************************************************/
-
-               /* We need space for additional instruction so we can
-                  translate these instructions to sequences of ICMD_COPY and
-                  ICMD_MOVE instructions. */
-
-               case BC_dup_x1:
-                       INSTRUCTIONS_CHECK(4);
-                       OP(opcode);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       break;
-
-               case BC_dup_x2:
-                       INSTRUCTIONS_CHECK(6);
-                       OP(opcode);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       break;
-
-               case BC_dup2:
-                       INSTRUCTIONS_CHECK(2);
-                       OP(opcode);
-                       OP(ICMD_NOP);
-                       break;
-
-               case BC_dup2_x1:
-                       INSTRUCTIONS_CHECK(7);
-                       OP(opcode);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       break;
-
-               case BC_dup2_x2:
-                       INSTRUCTIONS_CHECK(9);
-                       OP(opcode);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       break;
-
-               case BC_swap:
-                       INSTRUCTIONS_CHECK(3);
-                       OP(opcode);
-                       OP(ICMD_NOP);
-                       OP(ICMD_NOP);
-                       break;
-
-               /* local variable access instructions *********************************/
-
-               case BC_iload:
-               case BC_fload:
-               case BC_aload:
-                       if (iswide == false) {
-                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
-                       }
-                       else {
-                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                               nextbc = bcindex + 3;
-                               iswide = false;
-                       }
-                       OP_LOAD_ONEWORD(opcode, i, opcode - BC_iload);
-                       break;
-
-               case BC_lload:
-               case BC_dload:
-                       if (iswide == false) {
-                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
-                       }
-                       else {
-                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                               nextbc = bcindex + 3;
-                               iswide = false;
-                       }
-                       OP_LOAD_TWOWORD(opcode, i, opcode - BC_iload);
-                       break;
-
-               case BC_iload_0:
-               case BC_iload_1:
-               case BC_iload_2:
-               case BC_iload_3:
-                       OP_LOAD_ONEWORD(ICMD_ILOAD, opcode - BC_iload_0, TYPE_INT);
-                       break;
-
-               case BC_lload_0:
-               case BC_lload_1:
-               case BC_lload_2:
-               case BC_lload_3:
-                       OP_LOAD_TWOWORD(ICMD_LLOAD, opcode - BC_lload_0, TYPE_LNG);
-                       break;
-
-               case BC_fload_0:
-               case BC_fload_1:
-               case BC_fload_2:
-               case BC_fload_3:
-                       OP_LOAD_ONEWORD(ICMD_FLOAD, opcode - BC_fload_0, TYPE_FLT);
-                       break;
-
-               case BC_dload_0:
-               case BC_dload_1:
-               case BC_dload_2:
-               case BC_dload_3:
-                       OP_LOAD_TWOWORD(ICMD_DLOAD, opcode - BC_dload_0, TYPE_DBL);
-                       break;
-
-               case BC_aload_0:
-               case BC_aload_1:
-               case BC_aload_2:
-               case BC_aload_3:
-                       OP_LOAD_ONEWORD(ICMD_ALOAD, opcode - BC_aload_0, TYPE_ADR);
-                       break;
-
-               case BC_istore:
-               case BC_fstore:
-               case BC_astore:
-                       if (iswide == false) {
-                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
-                       }
-                       else {
-                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                               nextbc = bcindex + 3;
-                               iswide = false;
-                       }
-                       OP_STORE_ONEWORD(opcode, i, opcode - BC_istore);
-                       break;
-
-               case BC_lstore:
-               case BC_dstore:
-                       if (iswide == false) {
-                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
-                       }
-                       else {
-                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                               nextbc = bcindex + 3;
-                               iswide = false;
-                       }
-                       OP_STORE_TWOWORD(opcode, i, opcode - BC_istore);
-                       break;
-
-               case BC_istore_0:
-               case BC_istore_1:
-               case BC_istore_2:
-               case BC_istore_3:
-                       OP_STORE_ONEWORD(ICMD_ISTORE, opcode - BC_istore_0, TYPE_INT);
-                       break;
-
-               case BC_lstore_0:
-               case BC_lstore_1:
-               case BC_lstore_2:
-               case BC_lstore_3:
-                       OP_STORE_TWOWORD(ICMD_LSTORE, opcode - BC_lstore_0, TYPE_LNG);
-                       break;
-
-               case BC_fstore_0:
-               case BC_fstore_1:
-               case BC_fstore_2:
-               case BC_fstore_3:
-                       OP_STORE_ONEWORD(ICMD_FSTORE, opcode - BC_fstore_0, TYPE_FLT);
-                       break;
-
-               case BC_dstore_0:
-               case BC_dstore_1:
-               case BC_dstore_2:
-               case BC_dstore_3:
-                       OP_STORE_TWOWORD(ICMD_DSTORE, opcode - BC_dstore_0, TYPE_DBL);
-                       break;
-
-               case BC_astore_0:
-               case BC_astore_1:
-               case BC_astore_2:
-               case BC_astore_3:
-                       OP_STORE_ONEWORD(ICMD_ASTORE, opcode - BC_astore_0, TYPE_ADR);
-                       break;
-
-               case BC_iinc:
-                       {
-                               int v;
-
-                               if (iswide == false) {
-                                       i = SUCK_BE_U1(m->jcode + bcindex + 1);
-                                       v = SUCK_BE_S1(m->jcode + bcindex + 2);
-                               }
-                               else {
-                                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                                       v = SUCK_BE_S2(m->jcode + bcindex + 3);
-                                       nextbc = bcindex + 5;
-                                       iswide = false;
-                               }
-                               INDEX_ONEWORD(i);
-                               LOCALTYPE_USED(i, TYPE_INT);
-                               OP_LOCALINDEX_I(opcode, i, v);
-                       }
-                       break;
-
-               /* wider index for loading, storing and incrementing ******************/
-
-               case BC_wide:
-                       bcindex++;
-                       iswide = true;
-                       goto fetch_opcode;
-
-               /* managing arrays ****************************************************/
-
-               case BC_newarray:
-                       switch (SUCK_BE_S1(m->jcode + bcindex + 1)) {
-                       case 4:
-                               bte = builtintable_get_internal(BUILTIN_newarray_boolean);
-                               break;
-                       case 5:
-                               bte = builtintable_get_internal(BUILTIN_newarray_char);
-                               break;
-                       case 6:
-                               bte = builtintable_get_internal(BUILTIN_newarray_float);
-                               break;
-                       case 7:
-                               bte = builtintable_get_internal(BUILTIN_newarray_double);
-                               break;
-                       case 8:
-                               bte = builtintable_get_internal(BUILTIN_newarray_byte);
-                               break;
-                       case 9:
-                               bte = builtintable_get_internal(BUILTIN_newarray_short);
-                               break;
-                       case 10:
-                               bte = builtintable_get_internal(BUILTIN_newarray_int);
-                               break;
-                       case 11:
-                               bte = builtintable_get_internal(BUILTIN_newarray_long);
-                               break;
-#if defined(ENABLE_VERIFIER)
-                       default:
-                               exceptions_throw_verifyerror(m, "Invalid array-type to create");
-                               return false;
-#endif
-                       }
-                       OP_BUILTIN_CHECK_EXCEPTION(bte);
-                       break;
-
-               case BC_anewarray:
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       compr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
-                       if (compr == NULL)
-                               return false;
-
-                       if (!(cr = class_get_classref_multiarray_of(1, compr)))
-                               return false;
-
-                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
-                               return false;
-
-                       INSTRUCTIONS_CHECK(2);
-                       OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
-                       bte = builtintable_get_internal(BUILTIN_newarray);
-                       OP_BUILTIN_CHECK_EXCEPTION(bte);
-                       s_count++;
-                       break;
-
-               case BC_multianewarray:
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       j = SUCK_BE_U1(m->jcode + bcindex + 3);
-  
-                       cr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
-                       if (cr == NULL)
-                               return false;
-  
-                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
-                               return false;
-  
-                       /* if unresolved, c == NULL */
-  
-                       iptr->s1.argcount = j;
-                       OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, INS_FLAG_CHECK);
-                       code_unflag_leafmethod(code);
-                       break;
-
-               /* control flow instructions ******************************************/
-
-               case BC_ifeq:
-               case BC_iflt:
-               case BC_ifle:
-               case BC_ifne:
-               case BC_ifgt:
-               case BC_ifge:
-               case BC_ifnull:
-               case BC_ifnonnull:
-               case BC_if_icmpeq:
-               case BC_if_icmpne:
-               case BC_if_icmplt:
-               case BC_if_icmpgt:
-               case BC_if_icmple:
-               case BC_if_icmpge:
-               case BC_if_acmpeq:
-               case BC_if_acmpne:
-               case BC_goto:
-                       i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
-                       CHECK_BYTECODE_INDEX(i);
-                       MARK_BASICBLOCK(&pd, i);
-                       blockend = true;
-                       OP_INSINDEX(opcode, i);
-                       break;
-
-               case BC_goto_w:
-                       i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
-                       CHECK_BYTECODE_INDEX(i);
-                       MARK_BASICBLOCK(&pd, i);
-                       blockend = true;
-                       OP_INSINDEX(ICMD_GOTO, i);
-                       break;
-
-               case BC_jsr:
-                       i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
-jsr_tail:
-                       CHECK_BYTECODE_INDEX(i);
-                       MARK_BASICBLOCK(&pd, i);
-                       blockend = true;
-                       OP_PREPARE_ZEROFLAGS(BC_jsr);
-                       iptr->sx.s23.s3.jsrtarget.insindex = i;
-                       PINC;
-                       break;
-
-               case BC_jsr_w:
-                       i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
-                       goto jsr_tail;
-
-               case BC_ret:
-                       if (iswide == false) {
-                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
-                       }
-                       else {
-                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                               nextbc = bcindex + 3;
-                               iswide = false;
-                       }
-                       blockend = true;
-
-                       OP_LOAD_ONEWORD(opcode, i, TYPE_ADR);
-                       break;
-
-               case BC_ireturn:
-               case BC_lreturn:
-               case BC_freturn:
-               case BC_dreturn:
-               case BC_areturn:
-               case BC_return:
-                       blockend = true;
-                       /* XXX ARETURN will need a flag in the typechecker */
-                       OP(opcode);
-                       break;
-
-               case BC_athrow:
-                       blockend = true;
-                       /* XXX ATHROW will need a flag in the typechecker */
-                       OP(opcode);
-                       break;
-
-
-               /* table jumps ********************************************************/
-
-               case BC_lookupswitch:
-                       {
-                               s4 num, j;
-                               lookup_target_t *lookup;
-#if defined(ENABLE_VERIFIER)
-                               s4 prevvalue = 0;
-#endif
-                               blockend = true;
-                               nextbc = MEMORY_ALIGN((bcindex + 1), 4);
-
-                               CHECK_END_OF_BYTECODE(nextbc + 8);
-
-                               OP_PREPARE_ZEROFLAGS(opcode);
-
-                               /* default target */
-
-                               j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
-                               iptr->sx.s23.s3.lookupdefault.insindex = j;
-                               nextbc += 4;
-                               CHECK_BYTECODE_INDEX(j);
-                               MARK_BASICBLOCK(&pd, j);
-
-                               /* number of pairs */
-
-                               num = SUCK_BE_U4(m->jcode + nextbc);
-                               iptr->sx.s23.s2.lookupcount = num;
-                               nextbc += 4;
-
-                               /* allocate the intermediate code table */
-
-                               lookup = DMNEW(lookup_target_t, num);
-                               iptr->dst.lookup = lookup;
-
-                               /* iterate over the lookup table */
-
-                               CHECK_END_OF_BYTECODE(nextbc + 8 * num);
-
-                               for (i = 0; i < num; i++) {
-                                       /* value */
-
-                                       j = SUCK_BE_S4(m->jcode + nextbc);
-                                       lookup->value = j;
-
-                                       nextbc += 4;
-
-#if defined(ENABLE_VERIFIER)
-                                       /* check if the lookup table is sorted correctly */
-
-                                       if (i && (j <= prevvalue)) {
-                                               exceptions_throw_verifyerror(m, "Unsorted lookup switch");
-                                               return false;
-                                       }
-                                       prevvalue = j;
-#endif
-                                       /* target */
-
-                                       j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
-                                       lookup->target.insindex = j;
-                                       lookup++;
-                                       nextbc += 4;
-                                       CHECK_BYTECODE_INDEX(j);
-                                       MARK_BASICBLOCK(&pd, j);
-                               }
-
-                               PINC;
-                               break;
-                       }
-
-               case BC_tableswitch:
-                       {
-                               s4 num, j;
-                               s4 deftarget;
-                               branch_target_t *table;
-
-                               blockend = true;
-                               nextbc = MEMORY_ALIGN((bcindex + 1), 4);
-
-                               CHECK_END_OF_BYTECODE(nextbc + 12);
-
-                               OP_PREPARE_ZEROFLAGS(opcode);
-
-                               /* default target */
-
-                               deftarget = bcindex + SUCK_BE_S4(m->jcode + nextbc);
-                               nextbc += 4;
-                               CHECK_BYTECODE_INDEX(deftarget);
-                               MARK_BASICBLOCK(&pd, deftarget);
-
-                               /* lower bound */
-
-                               j = SUCK_BE_S4(m->jcode + nextbc);
-                               iptr->sx.s23.s2.tablelow = j;
-                               nextbc += 4;
-
-                               /* upper bound */
-
-                               num = SUCK_BE_S4(m->jcode + nextbc);
-                               iptr->sx.s23.s3.tablehigh = num;
-                               nextbc += 4;
-
-                               /* calculate the number of table entries */
-
-                               num = num - j + 1;
-
-#if defined(ENABLE_VERIFIER)
-                               if (num < 1) {
-                                       exceptions_throw_verifyerror(m,
-                                                       "invalid TABLESWITCH: upper bound < lower bound");
-                                       return false;
-                               }
-#endif
-                               /* create the intermediate code table */
-                               /* the first entry is the default target */
-
-                               table = DMNEW(branch_target_t, 1 + num);
-                               iptr->dst.table = table;
-                               (table++)->insindex = deftarget;
-
-                               /* iterate over the target table */
-
-                               CHECK_END_OF_BYTECODE(nextbc + 4 * num);
-
-                               for (i = 0; i < num; i++) {
-                                       j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
-                                       (table++)->insindex = j;
-                                       nextbc += 4;
-                                       CHECK_BYTECODE_INDEX(j);
-                                       MARK_BASICBLOCK(&pd, j);
-                               }
-
-                               PINC;
-                               break;
-                       }
-
-
-               /* load and store of object fields ************************************/
-
-               case BC_aastore:
-                       OP(opcode);
-                       code_unflag_leafmethod(code);
-                       break;
-
-               case BC_getstatic:
-               case BC_putstatic:
-               case BC_getfield:
-               case BC_putfield:
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       fmi = class_getconstant(m->clazz, i, CONSTANT_Fieldref);
-
-                       if (fmi == NULL)
-                               return false;
-
-                       OP_PREPARE_ZEROFLAGS(opcode);
-                       iptr->sx.s23.s3.fmiref = fmi;
-
-                       /* only with -noverify, otherwise the typechecker does this */
-
-#if defined(ENABLE_VERIFIER)
-                       if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
-#endif
-                               result = resolve_field_lazy(m, fmi);
-
-                               if (result == resolveFailed)
-                                       return false;
-
-                               if (result != resolveSucceeded) {
-                                       uf = resolve_create_unresolved_field(m->clazz, m, iptr);
-
-                                       if (uf == NULL)
-                                               return false;
-
-                                       /* store the unresolved_field pointer */
-
-                                       iptr->sx.s23.s3.uf = uf;
-                                       iptr->flags.bits |= INS_FLAG_UNRESOLVED;
-                               }
-#if defined(ENABLE_VERIFIER)
-                       }
-#endif
-                       PINC;
-                       break;
-
-
-               /* method invocation **************************************************/
-
-               case BC_invokestatic:
-                       OP_PREPARE_ZEROFLAGS(opcode);
-
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       fmi = class_getconstant(m->clazz, i, CONSTANT_Methodref);
-
-                       if (fmi == NULL)
-                               return false;
-
-                       md = fmi->parseddesc.md;
-
-                       if (md->params == NULL)
-                               if (!descriptor_params_from_paramtypes(md, ACC_STATIC))
-                                       return false;
-
-                       goto invoke_method;
-
-               case BC_invokespecial:
-                       OP_PREPARE_FLAGS(opcode, INS_FLAG_CHECK);
-
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       fmi = class_getconstant(m->clazz, i, CONSTANT_Methodref);
-
-                       goto invoke_nonstatic_method;
-
-               case BC_invokeinterface:
-                       OP_PREPARE_ZEROFLAGS(opcode);
-
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       fmi = class_getconstant(m->clazz, i, CONSTANT_InterfaceMethodref);
-
-                       goto invoke_nonstatic_method;
-
-               case BC_invokevirtual:
-                       OP_PREPARE_ZEROFLAGS(opcode);
-
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       fmi = class_getconstant(m->clazz, i, CONSTANT_Methodref);
-
-invoke_nonstatic_method:
-                       if (fmi == NULL)
-                               return false;
-
-                       md = fmi->parseddesc.md;
-
-                       if (md->params == NULL)
-                               if (!descriptor_params_from_paramtypes(md, 0))
-                                       return false;
-
-invoke_method:
-                       code_unflag_leafmethod(code);
-
-                       iptr->sx.s23.s3.fmiref = fmi;
-
-                       /* only with -noverify, otherwise the typechecker does this */
-
-#if defined(ENABLE_VERIFIER)
-                       if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
-#endif
-                               result = resolve_method_lazy(m, fmi, 
-                                                                                        (opcode == BC_invokespecial));
-
-                               if (result == resolveFailed)
-                                       return false;
-
-                               if (result == resolveSucceeded) {
-                                       methodinfo *mi = iptr->sx.s23.s3.fmiref->p.method;
-
-                                       /* if this call is monomorphic, turn it into an
-                                          INVOKESPECIAL */
-
-                                       assert(IS_FMIREF_RESOLVED(iptr->sx.s23.s3.fmiref));
-
-                                       if ((iptr->opc == ICMD_INVOKEVIRTUAL)
-                                               && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
-                                       {
-                                               iptr->opc         = ICMD_INVOKESPECIAL;
-                                               iptr->flags.bits |= INS_FLAG_CHECK;
-                                       }
-                               }
-                               else {
-                                       um = resolve_create_unresolved_method(m->clazz, m, fmi,
-                                                       (opcode == BC_invokestatic),
-                                                       (opcode == BC_invokespecial));
-
-                                       if (um == NULL)
-                                               return false;
-
-                                       /* store the unresolved_method pointer */
-
-                                       iptr->sx.s23.s3.um = um;
-                                       iptr->flags.bits |= INS_FLAG_UNRESOLVED;
-                               }
-#if defined(ENABLE_VERIFIER)
-                       }
-#endif
-                       PINC;
-                       break;
-
-               /* instructions taking class arguments ********************************/
-
-               case BC_new:
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       cr = class_getconstant(m->clazz, i, CONSTANT_Class);
-
-                       if (cr == NULL)
-                               return false;
-
-                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
-                               return false;
-
-                       INSTRUCTIONS_CHECK(2);
-                       OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
-                       bte = builtintable_get_internal(BUILTIN_new);
-                       OP_BUILTIN_CHECK_EXCEPTION(bte);
-                       s_count++;
-                       break;
-
-               case BC_checkcast:
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       cr = class_getconstant(m->clazz, i, CONSTANT_Class);
-
-                       if (cr == NULL)
-                               return false;
-
-                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
-                               return false;
-
-                       if (cr->name->text[0] == '[') {
-                               /* array type cast-check */
-                               flags = INS_FLAG_CHECK | INS_FLAG_ARRAY;
-                               code_unflag_leafmethod(code);
-                       }
-                       else {
-                               /* object type cast-check */
-                               flags = INS_FLAG_CHECK;
-                       }
-                       OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, flags);
-                       break;
-
-               case BC_instanceof:
-                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
-                       cr = class_getconstant(m->clazz, i, CONSTANT_Class);
-
-                       if (cr == NULL)
-                               return false;
-
-                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
-                               return false;
-
-                       if (cr->name->text[0] == '[') {
-                               /* array type cast-check */
-                               INSTRUCTIONS_CHECK(2);
-                               OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
-                               bte = builtintable_get_internal(BUILTIN_arrayinstanceof);
-                               OP_BUILTIN_NO_EXCEPTION(bte);
-                               s_count++;
-                       }
-                       else {
-                               /* object type cast-check */
-                               OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, 0 /* flags*/);
-                       }
-                       break;
-
-               /* synchronization instructions ***************************************/
-
-               case BC_monitorenter:
-#if defined(ENABLE_THREADS)
-                       if (checksync) {
-                               bte = builtintable_get_internal(LOCK_monitor_enter);
-                               OP_BUILTIN_CHECK_EXCEPTION(bte);
-                       }
-                       else
-#endif
-                       {
-                               OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
-                               OP(ICMD_POP);
-                       }
-                       break;
-
-               case BC_monitorexit:
-#if defined(ENABLE_THREADS)
-                       if (checksync) {
-                               bte = builtintable_get_internal(LOCK_monitor_exit);
-                               OP_BUILTIN_CHECK_EXCEPTION(bte);
-                       }
-                       else
-#endif
-                       {
-                               OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
-                               OP(ICMD_POP);
-                       }
-                       break;
-
-               /* arithmetic instructions that may become builtin functions **********/
-
-               case BC_idiv:
-#if !SUPPORT_DIVISION
-                       bte = builtintable_get_internal(BUILTIN_idiv);
-                       OP_BUILTIN_ARITHMETIC(opcode, bte);
-#else
-# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
-                       OP(opcode);
-# else
-                       OP_CHECK_EXCEPTION(opcode);
-# endif
-#endif
-                       break;
-
-               case BC_irem:
-#if !SUPPORT_DIVISION
-                       bte = builtintable_get_internal(BUILTIN_irem);
-                       OP_BUILTIN_ARITHMETIC(opcode, bte);
-#else
-# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
-                       OP(opcode);
-# else
-                       OP_CHECK_EXCEPTION(opcode);
-# endif
-#endif
-                       break;
-
-               case BC_ldiv:
-#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
-                       bte = builtintable_get_internal(BUILTIN_ldiv);
-                       OP_BUILTIN_ARITHMETIC(opcode, bte);
-#else
-# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
-                       OP(opcode);
-# else
-                       OP_CHECK_EXCEPTION(opcode);
-# endif
-#endif
-                       break;
-
-               case BC_lrem:
-#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
-                       bte = builtintable_get_internal(BUILTIN_lrem);
-                       OP_BUILTIN_ARITHMETIC(opcode, bte);
-#else
-# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
-                       OP(opcode);
-# else
-                       OP_CHECK_EXCEPTION(opcode);
-# endif
-#endif
-                       break;
-
-               case BC_frem:
-#if defined(__I386__)
-                       OP(opcode);
-#else
-                       bte = builtintable_get_internal(BUILTIN_frem);
-                       OP_BUILTIN_NO_EXCEPTION(bte);
-#endif
-                       break;
-
-               case BC_drem:
-#if defined(__I386__)
-                       OP(opcode);
-#else
-                       bte = builtintable_get_internal(BUILTIN_drem);
-                       OP_BUILTIN_NO_EXCEPTION(bte);
-#endif
-                       break;
-
-               case BC_f2i:
-#if defined(__ALPHA__)
-                       bte = builtintable_get_internal(BUILTIN_f2i);
-                       OP_BUILTIN_NO_EXCEPTION(bte);
-#else
-                       OP(opcode);
-#endif
-                       break;
-
-               case BC_f2l:
-#if defined(__ALPHA__)
-                       bte = builtintable_get_internal(BUILTIN_f2l);
-                       OP_BUILTIN_NO_EXCEPTION(bte);
-#else
-                       OP(opcode);
-#endif
-                       break;
-
-               case BC_d2i:
-#if defined(__ALPHA__)
-                       bte = builtintable_get_internal(BUILTIN_d2i);
-                       OP_BUILTIN_NO_EXCEPTION(bte);
-#else
-                       OP(opcode);
-#endif
-                       break;
-
-               case BC_d2l:
-#if defined(__ALPHA__)
-                       bte = builtintable_get_internal(BUILTIN_d2l);
-                       OP_BUILTIN_NO_EXCEPTION(bte);
-#else
-                       OP(opcode);
-#endif
-                       break;
-
-
-               /* invalid opcodes ****************************************************/
-
-                       /* check for invalid opcodes if the verifier is enabled */
-#if defined(ENABLE_VERIFIER)
-               case BC_breakpoint:
-                       exceptions_throw_verifyerror(m, "Quick instructions shouldn't appear, yet.");
-                       return false;
-
-
-               /* Unused opcodes ************************************************** */
-
-               case 186:
-               case 203:
-               case 204:
-               case 205:
-               case 206:
-               case 207:
-               case 208:
-               case 209:
-               case 210:
-               case 211:
-               case 212:
-               case 213:
-               case 214:
-               case 215:
-               case 216:
-               case 217:
-               case 218:
-               case 219:
-               case 220:
-               case 221:
-               case 222:
-               case 223:
-               case 224:
-               case 225:
-               case 226:
-               case 227:
-               case 228:
-               case 229:
-               case 230:
-               case 231:
-               case 232:
-               case 233:
-               case 234:
-               case 235:
-               case 236:
-               case 237:
-               case 238:
-               case 239:
-               case 240:
-               case 241:
-               case 242:
-               case 243:
-               case 244:
-               case 245:
-               case 246:
-               case 247:
-               case 248:
-               case 249:
-               case 250:
-               case 251:
-               case 252:
-               case 253:
-               case 254:
-               case 255:
-                       exceptions_throw_verifyerror(m, "Illegal opcode %d at instr %d\n",
-                                                                                opcode, ircount);
-                       return false;
-                       break;
-#endif /* defined(ENABLE_VERIFIER) */
-
-               /* opcodes that don't require translation *****************************/
-
-               default:
-                       /* Straight-forward translation to HIR. */
-                       OP(opcode);
-                       break;
-
-               } /* end switch */
-
-               /* verifier checks ****************************************************/
-
-#if defined(ENABLE_VERIFIER)
-               /* If WIDE was used correctly, iswide should have been reset by now. */
-               if (iswide) {
-                       exceptions_throw_verifyerror(m,
-                                       "Illegal instruction: WIDE before incompatible opcode");
-                       return false;
-               }
-#endif /* defined(ENABLE_VERIFIER) */
-
-       } /* end for */
-
-       if (JITDATA_HAS_FLAG_REORDER(jd)) {
-               /* add a NOP to the last basic block */
-
-               INSTRUCTIONS_CHECK(1);
-               OP(ICMD_NOP);
-       }
-
-       /*** END OF LOOP **********************************************************/
-
-       /* assert that we did not write more ICMDs than allocated */
-
-       assert(ircount <= pd.instructionslength);
-       assert(ircount == (iptr - pd.instructions));
-
-       /*** verifier checks ******************************************************/
-
-#if defined(ENABLE_VERIFIER)
-       if (bcindex != m->jcodelength) {
-               exceptions_throw_verifyerror(m,
-                               "Command-sequence crosses code-boundary");
-               return false;
-       }
-
-       if (!blockend) {
-               exceptions_throw_verifyerror(m, "Falling off the end of the code");
-               return false;
-       }
-#endif /* defined(ENABLE_VERIFIER) */
-
-       /*** setup the methodinfo, allocate stack and basic blocks ****************/
-
-       /* identify basic blocks */
-
-       /* check if first instruction is a branch target */
-
-       if (pd.basicblockstart[0] == 1) {
-               jd->branchtoentry = true;
-       }
-       else {
-               /* first instruction always starts a basic block */
-
-               iptr = pd.instructions;
-
-               iptr->flags.bits |= INS_FLAG_BASICBLOCK;
-       }
-
-       /* Iterate over all bytecode instructions and set missing
-          basic-block starts in IR instructions. */
-
-       for (bcindex = 0; bcindex < m->jcodelength; bcindex++) {
-               /* Does the current bytecode instruction start a basic
-                  block? */
-
-               if (pd.basicblockstart[bcindex] == 1) {
-#if defined(ENABLE_VERIFIER)
-                       /* Check if this bytecode basic-block start at the
-                          beginning of a bytecode instruction. */
-
-                       if (pd.bytecodestart[bcindex] == 0) {
-                               exceptions_throw_verifyerror(m,
-                                                                                "Branch into middle of instruction");
-                               return false;
-                       }
-#endif
-
-                       /* Get the IR instruction mapped to the bytecode
-                          instruction and set the basic block flag. */
-
-                       irindex = pd.bytecodemap[bcindex];
-                       iptr    = pd.instructions + irindex;
-
-                       iptr->flags.bits |= INS_FLAG_BASICBLOCK;
-               }
-       }
-
-       /* IR instruction index to basic-block index mapping */
-
-       pd.instructionmap = DMNEW(s4, ircount);
-       MZERO(pd.instructionmap, s4, ircount);
-
-       /* Iterate over all IR instructions and count the basic blocks. */
-
-       iptr = pd.instructions;
-
-       bbcount = 0;
-
-       for (i = 0; i < ircount; i++, iptr++) {
-               if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
-                       /* store the basic-block number in the IR instruction
-                          map */
-
-                       pd.instructionmap[i] = bbcount;
-
-                       /* post-increment the basic-block count */
-
-                       bbcount++;
-               }
-       }
-
-       /* Allocate basic block array (one more for end ipc). */
-
-       jd->basicblocks = DMNEW(basicblock, bbcount + 1);
-       MZERO(jd->basicblocks, basicblock, bbcount + 1);
-
-       /* Now iterate again over all IR instructions and initialize the
-          basic block structures and, in the same loop, resolve the
-          branch-target instruction indices to basic blocks. */
-
-       iptr = pd.instructions;
-       bptr = jd->basicblocks;
-
-       bbcount = 0;
-
-       for (i = 0; i < ircount; i++, iptr++) {
-               /* check for basic block */
-
-               if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
-                       /* intialize the basic block */
-
-                       BASICBLOCK_INIT(bptr, m);
-
-                       bptr->iinstr = iptr;
-
-                       if (bbcount > 0) {
-                               bptr[-1].icount = bptr->iinstr - bptr[-1].iinstr;
-                       }
-
-                       /* bptr->icount is set when the next block is allocated */
-
-                       bptr->nr = bbcount++;
-                       bptr++;
-                       bptr[-1].next = bptr;
-               }
-
-               /* resolve instruction indices to basic blocks */
-
-               switch (iptr->opc) {
-               case ICMD_IFEQ:
-               case ICMD_IFLT:
-               case ICMD_IFLE:
-               case ICMD_IFNE:
-               case ICMD_IFGT:
-               case ICMD_IFGE:
-               case ICMD_IFNULL:
-               case ICMD_IFNONNULL:
-               case ICMD_IF_ICMPEQ:
-               case ICMD_IF_ICMPNE:
-               case ICMD_IF_ICMPLT:
-               case ICMD_IF_ICMPGT:
-               case ICMD_IF_ICMPLE:
-               case ICMD_IF_ICMPGE:
-               case ICMD_IF_ACMPEQ:
-               case ICMD_IF_ACMPNE:
-               case ICMD_GOTO:
-                       BYTECODEINDEX_TO_BASICBLOCK(iptr->dst);
-                       break;
-
-               case ICMD_JSR:
-                       BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.jsrtarget);
-                       break;
-
-               case ICMD_TABLESWITCH:
-                       table = iptr->dst.table;
-
-                       BYTECODEINDEX_TO_BASICBLOCK(*table);
-                       table++;
-
-                       j = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1;
-
-                       while (--j >= 0) {
-                               BYTECODEINDEX_TO_BASICBLOCK(*table);
-                               table++;
-                       }
-                       break;
-
-               case ICMD_LOOKUPSWITCH:
-                       BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.lookupdefault);
-
-                       lookup = iptr->dst.lookup;
-
-                       j = iptr->sx.s23.s2.lookupcount;
-
-                       while (--j >= 0) {
-                               BYTECODEINDEX_TO_BASICBLOCK(lookup->target);
-                               lookup++;
-                       }
-                       break;
-               }
-       }
-
-       /* set instruction count of last real block */
-
-       if (bbcount > 0) {
-               bptr[-1].icount = (pd.instructions + ircount) - bptr[-1].iinstr;
-       }
-
-       /* allocate additional block at end */
-
-       BASICBLOCK_INIT(bptr, m);
-       bptr->nr = bbcount;
-
-       /* set basicblock pointers in exception table */
-
-       if (!parse_resolve_exception_table(jd, &pd))
-               return false;
-
-       /* store the local map */
-
-       jd->local_map = local_map;
-
-       /* calculate local variable renaming */
-
-       {
-               s4 nlocals = 0;
-               s4 i;
-               s4 t;
-               s4 varindex;
-               s4 *mapptr;
-               s4 *reversemap;
-
-               mapptr = local_map;
-
-               /* iterate over local_map[0..m->maxlocals*5-1] and allocate a unique */
-               /* variable index for each _used_ (javaindex,type) pair.             */
-               /* (local_map[javaindex*5+type] = cacaoindex)                        */
-               /* Unused (javaindex,type) pairs are marked with UNUSED.             */
-
-               for (i = 0; i < (m->maxlocals * 5); i++, mapptr++) {
-                       if (*mapptr)
-                               *mapptr = nlocals++;
-                       else
-                               *mapptr = UNUSED;
-               }
-
-               jd->localcount = nlocals;
-
-               /* calculate the (maximum) number of variables needed */
-
-               jd->varcount = 
-                         nlocals                                      /* local variables */
-                       + bbcount * m->maxstack                                 /* invars */
-                       + s_count;         /* variables created within blocks (non-invar) */
-
-               /* reserve the first indices for local variables */
-
-               jd->vartop = nlocals;
-
-               /* reserve extra variables needed by stack analyse */
-
-               jd->varcount += STACK_EXTRA_VARS;
-               jd->vartop   += STACK_EXTRA_VARS;
-
-               /* The verifier needs space for saving invars in some cases and */
-               /* extra variables.                                             */
-
-#if defined(ENABLE_VERIFIER)
-               jd->varcount += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
-               jd->vartop   += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
-#endif
-               /* allocate and initialize the variable array */
-
-               jd->var = DMNEW(varinfo, jd->varcount);
-               MZERO(jd->var, varinfo, jd->varcount);
-
-               /* set types of all locals in jd->var */
-               /* and fill the reverselocalmap       */
-
-               reversemap = DMNEW(s4, nlocals);
-
-               for (i = 0; i < m->maxlocals; i++)
-                       for (t=0; t<5; t++) {
-                               varindex = local_map[5*i + t];
-                               if (varindex != UNUSED) {
-                                       VAR(varindex)->type = t;
-                                       reversemap[varindex] = i;
-                               }
-                       }
-
-               jd->reverselocalmap = reversemap;
-       }
-
-       /* assign local variables to method variables */
-
-       jd->instructions     = pd.instructions;
-       jd->instructioncount = ircount;
-       jd->basicblockcount  = bbcount;
-       jd->stackcount       = s_count + bbcount * m->maxstack; /* in-stacks */
-
-       /* allocate stack table */
-
-       jd->stack = DMNEW(stackelement_t, jd->stackcount);
-
-       /* everything's ok */
-
-       return true;
-
-       /*** goto labels for throwing verifier exceptions *************************/
-
-#if defined(ENABLE_VERIFIER)
-
-throw_unexpected_end_of_bytecode:
-       exceptions_throw_verifyerror(m, "Unexpected end of bytecode");
-       return false;
-
-throw_invalid_bytecode_index:
-       exceptions_throw_verifyerror(m, "Illegal target of branch instruction");
-       return false;
-
-throw_illegal_local_variable_number:
-       exceptions_throw_verifyerror(m, "Illegal local variable number");
-       return false;
-
-#endif /* ENABLE_VERIFIER */
-}
-
-
-/*
- * 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/jit/parse.cpp b/src/vm/jit/parse.cpp
new file mode 100644 (file)
index 0000000..63a15bb
--- /dev/null
@@ -0,0 +1,1928 @@
+/* src/vm/jit/parse.c - parser for JavaVM to intermediate code translation
+
+   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 <string.h>
+
+#include "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "native/native.hpp"
+
+#include "threads/lock.hpp"
+
+#include "toolbox/logging.h"
+
+#include "vm/jit/builtin.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/linker.hpp"
+#include "vm/loader.hpp"
+#include "vm/options.h"
+#include "vm/resolve.hpp"
+
+#if defined(ENABLE_STATISTICS)
+# include "vm/statistics.h"
+#endif
+
+#include "vm/string.hpp"
+#include "vm/suck.hpp"
+
+#include "vm/jit/asmpart.h"
+#include "vm/jit/jit.hpp"
+#include "vm/jit/parse.hpp"
+#include "vm/jit/loop/loop.h"
+
+#include "vm/jit/ir/bytecode.h"
+
+
+#define INSTRUCTIONS_INCREMENT  5  /* number of additional instructions to    */
+                                   /* allocate if space runs out              */
+
+
+/* local macros ***************************************************************/
+
+#define BYTECODEINDEX_TO_BASICBLOCK(dst) \
+    do { \
+        (dst).block = \
+            parse_bytecodeindex_to_basicblock(jd, &pd, (dst).insindex); \
+    } while (0)
+
+
+/* parserdata_t ***************************************************************/
+
+typedef struct parsedata_t parsedata_t;
+
+struct parsedata_t {
+       u1          *bytecodestart;         /* start of bytecode instructions     */
+       u1          *basicblockstart;       /* start of bytecode basic-blocks     */
+
+       s4          *bytecodemap;           /* bytecode to IR mapping             */
+       
+       instruction *instructions;          /* instruction array                  */
+       s4           instructionslength;    /* length of the instruction array    */
+
+       s4          *instructionmap;        /* IR to basic-block mapping          */
+};
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* parse_setup *****************************************************************
+
+   Fills the passed parsedata_t structure.
+
+*******************************************************************************/
+
+static void parse_setup(jitdata *jd, parsedata_t *pd)
+{
+       methodinfo *m;
+
+       /* get required compiler data */
+
+       m = jd->m;
+
+       /* bytecode start array */
+
+       pd->bytecodestart = (u1*) DumpMemory::allocate(sizeof(u1) * (m->jcodelength + 1));
+       MZERO(pd->bytecodestart, u1, m->jcodelength + 1);
+
+       /* bytecode basic-block start array */
+
+       pd->basicblockstart = (u1*) DumpMemory::allocate(sizeof(u1) *(m->jcodelength + 1));
+       MZERO(pd->basicblockstart, u1, m->jcodelength + 1);
+
+       /* bytecode instruction index to IR instruction mapping */
+
+       pd->bytecodemap = (s4*) DumpMemory::allocate(sizeof(s4) * (m->jcodelength + 1));
+       MSET(pd->bytecodemap, -1, s4, m->jcodelength + 1);
+
+       /* allocate the instruction array */
+
+       pd->instructionslength = m->jcodelength + 1;
+       pd->instructions = (instruction*) DumpMemory::allocate(sizeof(instruction) * pd->instructionslength);
+
+       /* Zero the intermediate instructions array so we don't have any
+          invalid pointers in it if we cannot finish stack_analyse(). */
+
+       MZERO(pd->instructions, instruction, pd->instructionslength);
+
+       /* The instructionmap is allocated later when we know the count of
+          instructions. */
+
+       pd->instructionmap = NULL;
+}
+
+
+/* parse_realloc_instructions **************************************************
+
+   Reallocate the instructions array so there is room for at least N 
+   additional instructions.
+
+   RETURN VALUE:
+       the new value for iptr
+
+*******************************************************************************/
+
+static instruction *parse_realloc_instructions(parsedata_t *pd, s4 icount, s4 n)
+{
+       /* increase the size of the instruction array */
+
+       pd->instructionslength += (n + INSTRUCTIONS_INCREMENT);
+
+       /* reallocate the array */
+
+       pd->instructions = (instruction*) DumpMemory::reallocate(pd->instructions, sizeof(instruction) * icount,
+                                                                sizeof(instruction) * pd->instructionslength);
+       MZERO(pd->instructions + icount, instruction,
+                 (pd->instructionslength - icount));
+
+       /* return the iptr */
+
+       return pd->instructions + icount;
+}
+
+
+/* parse_bytecodeindex_to_basicblock *******************************************
+
+   Resolves a bytecode index to the corresponding basic block.
+
+*******************************************************************************/
+
+static basicblock *parse_bytecodeindex_to_basicblock(jitdata *jd,
+                                                                                                        parsedata_t *pd,
+                                                                                                        s4 bcindex)
+{
+       s4          irindex;
+       basicblock *bb;
+
+       irindex = pd->bytecodemap[bcindex];
+       bb      = jd->basicblocks + pd->instructionmap[irindex];
+
+       return bb;
+}
+
+
+/* parse_mark_exception_boundaries *********************************************
+
+   Mark exception handlers and the boundaries of the handled regions as
+   basic block boundaries.
+
+   IN:
+       jd...............current jitdata
+
+   RETURN VALUE:
+       true.............everything ok
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+static bool parse_mark_exception_boundaries(jitdata *jd, parsedata_t *pd)
+{
+       s4                   bcindex;
+       s4                   i;
+       s4                   len;
+       raw_exception_entry *rex;
+       methodinfo          *m;
+
+       m = jd->m;
+       
+       len = m->rawexceptiontablelength;
+
+       if (len == 0)
+               return true;
+
+       rex = m->rawexceptiontable;
+
+       for (i = 0; i < len; ++i, ++rex) {
+
+               /* the start of the handled region becomes a basic block start */
+
+               bcindex = rex->startpc;
+               CHECK_BYTECODE_INDEX(bcindex);
+               MARK_BASICBLOCK(pd, bcindex);
+               
+               bcindex = rex->endpc; /* see JVM Spec 4.7.3 */
+               CHECK_BYTECODE_INDEX_EXCLUSIVE(bcindex);
+
+               /* check that the range is valid */
+
+#if defined(ENABLE_VERIFIER)
+               if (bcindex <= rex->startpc) {
+                       exceptions_throw_verifyerror(m, "Invalid exception handler range");
+                       return false;
+               }
+#endif
+               
+               /* End of handled region becomes a basic block boundary (if it
+                  is the bytecode end, we'll use the special end block that
+                  is created anyway). */
+
+               if (bcindex < m->jcodelength)
+                       MARK_BASICBLOCK(pd, bcindex);
+               else
+                       jd->branchtoend = true;
+
+               /* the start of the handler becomes a basic block start  */
+
+               bcindex = rex->handlerpc;
+               CHECK_BYTECODE_INDEX(bcindex);
+               MARK_BASICBLOCK(pd, bcindex);
+       }
+
+       /* everything ok */
+
+       return true;
+
+#if defined(ENABLE_VERIFIER)
+throw_invalid_bytecode_index:
+       exceptions_throw_verifyerror(m,
+                                                                "Illegal bytecode index in exception table");
+       return false;
+#endif
+}
+
+
+/* parse_resolve_exception_table ***********************************************
+
+   Enter the exception handlers and their ranges, resolved to basicblock *s,
+   in the jitdata.
+
+   IN:
+       jd...............current jitdata
+
+   RETURN VALUE:
+          true.............everything ok
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+static bool parse_resolve_exception_table(jitdata *jd, parsedata_t *pd)
+{
+       methodinfo          *m;
+       raw_exception_entry *rex;
+       exception_entry     *ex;
+       s4                   i;
+       s4                   len;
+       classinfo           *exclass;
+
+       m = jd->m;
+
+       len = m->rawexceptiontablelength;
+
+       /* common case: no handler entries */
+
+       if (len == 0)
+               return true;
+
+       /* allocate the exception table */
+
+       jd->exceptiontablelength = len;
+       jd->exceptiontable = (exception_entry*) DumpMemory::allocate(sizeof(exception_entry) * (len + 1)); /* XXX why +1? */
+
+       /* copy and resolve the entries */
+
+       ex = jd->exceptiontable;
+       rex = m->rawexceptiontable;
+
+       for (i = 0; i < len; ++i, ++rex, ++ex) {
+               /* resolve instruction indices to basic blocks */
+
+               ex->start   = parse_bytecodeindex_to_basicblock(jd, pd, rex->startpc);
+               ex->end     = parse_bytecodeindex_to_basicblock(jd, pd, rex->endpc);
+               ex->handler = parse_bytecodeindex_to_basicblock(jd, pd, rex->handlerpc);
+
+               /* lazily resolve the catchtype */
+
+               if (rex->catchtype.any != NULL) {
+                       if (!resolve_classref_or_classinfo(m,
+                                                                                          rex->catchtype,
+                                                                                          resolveLazy, true, false,
+                                                                                          &exclass))
+                               return false;
+
+                       /* if resolved, enter the result of resolution in the table */
+
+                       if (exclass != NULL)
+                               rex->catchtype.cls = exclass;
+               }
+
+               ex->catchtype = rex->catchtype;
+               ex->next = NULL;   /* set by loop analysis */
+               ex->down = ex + 1; /* link to next exception entry */
+       }
+
+       /* terminate the ->down linked list */
+
+       assert(ex != jd->exceptiontable);
+       ex[-1].down = NULL;
+
+       return true;
+}
+
+
+/*******************************************************************************
+
+       function 'parse' scans the JavaVM code and generates intermediate code
+
+       During parsing the block index table is used to store at bit pos 0
+       a flag which marks basic block starts and at position 1 to 31 the
+       intermediate instruction index. After parsing the block index table
+       is scanned, for marked positions a block is generated and the block
+       number is stored in the block index table.
+
+*******************************************************************************/
+
+/*** macro for checking the length of the bytecode ***/
+
+#if defined(ENABLE_VERIFIER)
+#define CHECK_END_OF_BYTECODE(neededlength) \
+       do { \
+               if ((neededlength) > m->jcodelength) \
+                       goto throw_unexpected_end_of_bytecode; \
+       } while (0)
+#else /* !ENABLE_VERIFIER */
+#define CHECK_END_OF_BYTECODE(neededlength)
+#endif /* ENABLE_VERIFIER */
+
+bool parse(jitdata *jd)
+{
+       methodinfo  *m;                     /* method being parsed                */
+       codeinfo    *code;
+       parsedata_t  pd;
+       instruction *iptr;                  /* current ptr into instruction array */
+
+       s4           bcindex;               /* bytecode instruction index         */
+       s4           nextbc;                /* start of next bytecode instruction */
+       s4           opcode;                /* bytecode instruction opcode        */
+
+       s4           irindex;               /* IR instruction index               */
+       s4           ircount;               /* IR instruction count               */
+
+       s4           bbcount;               /* basic block count                  */
+
+       int  s_count = 0;             /* stack element counter                    */
+       bool blockend;                /* true if basic block end has been reached */
+       bool iswide;                  /* true if last instruction was a wide      */
+
+       constant_classref  *cr;
+       constant_classref  *compr;
+       classinfo          *c;
+       builtintable_entry *bte;
+       constant_FMIref    *fmi;
+       methoddesc         *md;
+       unresolved_method  *um;
+       unresolved_field   *uf;
+
+       resolve_result_t    result;
+       u2                  lineindex = 0;
+       u2                  currentline = 0;
+       u2                  linepcchange = 0;
+       u4                  flags;
+       basicblock         *bptr;
+
+       int                *local_map; /* local pointer to renaming map           */
+                                      /* is assigned to rd->local_map at the end */
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       s4               i;
+       s4               j;
+
+       /* get required compiler data */
+
+       m    = jd->m;
+       code = jd->code;
+
+       /* allocate buffers for local variable renaming */
+
+       local_map = (int*) DumpMemory::allocate(sizeof(int) * m->maxlocals * 5);
+
+       for (i = 0; i < m->maxlocals; i++) {
+               local_map[i * 5 + 0] = 0;
+               local_map[i * 5 + 1] = 0;
+               local_map[i * 5 + 2] = 0;
+               local_map[i * 5 + 3] = 0;
+               local_map[i * 5 + 4] = 0;
+       }
+
+       /* initialize the parse data structures */
+  
+       parse_setup(jd, &pd);
+  
+       /* initialize local variables */
+  
+       iptr     = pd.instructions;
+       ircount  = 0;
+       bbcount  = 0;
+       blockend = false;
+       iswide   = false;
+
+       /* mark basic block boundaries for exception table */
+
+       if (!parse_mark_exception_boundaries(jd, &pd))
+               return false;
+
+       /* initialize stack element counter */
+
+       s_count = 1 + m->rawexceptiontablelength;
+
+       /* setup line number info */
+
+       currentline = 0;
+       linepcchange = 0;
+
+       if (m->linenumbercount == 0) {
+               lineindex = 0;
+       }
+       else {
+               linepcchange = m->linenumbers[0].start_pc;
+       }
+
+       /*** LOOP OVER ALL BYTECODE INSTRUCTIONS **********************************/
+
+       for (bcindex = 0; bcindex < m->jcodelength; bcindex = nextbc) {
+
+               /* mark this position as a valid bytecode instruction start */
+
+               pd.bytecodestart[bcindex] = 1;
+
+               /* change the current line number, if necessary */
+
+               /* XXX rewrite this using pointer arithmetic */
+
+               if (linepcchange == bcindex) {
+                       if (m->linenumbercount > lineindex) {
+next_linenumber:
+                               currentline = m->linenumbers[lineindex].line_number;
+                               lineindex++;
+                               if (lineindex < m->linenumbercount) {
+                                       linepcchange = m->linenumbers[lineindex].start_pc;
+                                       if (linepcchange == bcindex)
+                                               goto next_linenumber;
+                               }
+                       }
+               }
+
+fetch_opcode:
+               /* fetch next opcode  */        
+
+               opcode = SUCK_BE_U1(m->jcode + bcindex);
+
+               /* If the previous instruction was a block-end instruction,
+                  mark the current bytecode instruction as basic-block
+                  starting instruction. */
+
+               /* NOTE: Some compilers put a BC_nop after a blockend
+                  instruction. */
+
+               if (blockend && (opcode != BC_nop)) {
+                       MARK_BASICBLOCK(&pd, bcindex);
+                       blockend = false;
+               }
+
+               /* If the current bytecode instruction was marked as
+                  basic-block starting instruction before (e.g. blockend,
+                  forward-branch target), mark the current IR instruction
+                  too. */
+
+               if (pd.basicblockstart[bcindex] != 0) {
+                       /* We need a NOP as last instruction in each basic block
+                          for basic block reordering (may be replaced with a GOTO
+                          later). */
+
+                       INSTRUCTIONS_CHECK(1);
+                       OP(ICMD_NOP);
+               }
+
+               /* store intermediate instruction count (bit 0 mark block starts) */
+
+               pd.bytecodemap[bcindex] = ircount;
+
+               /* compute next instruction start */
+
+               nextbc = bcindex + bytecode[opcode].length;
+
+               CHECK_END_OF_BYTECODE(nextbc);
+
+               /* add stack elements produced by this instruction */
+
+               s_count += bytecode[opcode].slots;
+
+               /* We check here for the space of 1 instruction in the
+                  instruction array.  If an opcode is converted to more than
+                  1 instruction, this is checked in the corresponding
+                  case. */
+
+               INSTRUCTIONS_CHECK(1);
+
+               /* translate this bytecode instruction */
+               switch (opcode) {
+
+               case BC_nop:
+                       break;
+
+               /* pushing constants onto the stack ***********************************/
+
+               case BC_bipush:
+                       OP_LOADCONST_I(SUCK_BE_S1(m->jcode + bcindex + 1));
+                       break;
+
+               case BC_sipush:
+                       OP_LOADCONST_I(SUCK_BE_S2(m->jcode + bcindex + 1));
+                       break;
+
+               case BC_ldc1:
+                       i = SUCK_BE_U1(m->jcode + bcindex + 1);
+                       goto pushconstantitem;
+
+               case BC_ldc2:
+               case BC_ldc2w:
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+
+               pushconstantitem:
+
+#if defined(ENABLE_VERIFIER)
+                       if (i >= m->clazz->cpcount) {
+                               exceptions_throw_verifyerror(m,
+                                       "Attempt to access constant outside range");
+                               return false;
+                       }
+#endif
+
+                       switch (m->clazz->cptags[i]) {
+                       case CONSTANT_Integer:
+                               OP_LOADCONST_I(((constant_integer *) (m->clazz->cpinfos[i]))->value);
+                               break;
+                       case CONSTANT_Long:
+                               OP_LOADCONST_L(((constant_long *) (m->clazz->cpinfos[i]))->value);
+                               break;
+                       case CONSTANT_Float:
+                               OP_LOADCONST_F(((constant_float *) (m->clazz->cpinfos[i]))->value);
+                               break;
+                       case CONSTANT_Double:
+                               OP_LOADCONST_D(((constant_double *) (m->clazz->cpinfos[i]))->value);
+                               break;
+                       case CONSTANT_String:
+                               OP_LOADCONST_STRING(literalstring_new((utf *) (m->clazz->cpinfos[i])));
+                               break;
+                       case CONSTANT_Class:
+                               cr = (constant_classref *) (m->clazz->cpinfos[i]);
+
+                               if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+                                       return false;
+
+                               /* if not resolved, c == NULL */
+
+                               OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr);
+
+                               break;
+
+#if defined(ENABLE_VERIFIER)
+                       default:
+                               exceptions_throw_verifyerror(m,
+                                               "Invalid constant type to push");
+                               return false;
+#endif
+                       }
+                       break;
+
+               case BC_aconst_null:
+                       OP_LOADCONST_NULL();
+                       break;
+
+               case BC_iconst_m1:
+               case BC_iconst_0:
+               case BC_iconst_1:
+               case BC_iconst_2:
+               case BC_iconst_3:
+               case BC_iconst_4:
+               case BC_iconst_5:
+                       OP_LOADCONST_I(opcode - BC_iconst_0);
+                       break;
+
+               case BC_lconst_0:
+               case BC_lconst_1:
+                       OP_LOADCONST_L(opcode - BC_lconst_0);
+                       break;
+
+               case BC_fconst_0:
+               case BC_fconst_1:
+               case BC_fconst_2:
+                       OP_LOADCONST_F(opcode - BC_fconst_0);
+                       break;
+
+               case BC_dconst_0:
+               case BC_dconst_1:
+                       OP_LOADCONST_D(opcode - BC_dconst_0);
+                       break;
+
+               /* stack operations ***************************************************/
+
+               /* We need space for additional instruction so we can
+                  translate these instructions to sequences of ICMD_COPY and
+                  ICMD_MOVE instructions. */
+
+               case BC_dup_x1:
+                       INSTRUCTIONS_CHECK(4);
+                       OP(opcode);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       break;
+
+               case BC_dup_x2:
+                       INSTRUCTIONS_CHECK(6);
+                       OP(opcode);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       break;
+
+               case BC_dup2:
+                       INSTRUCTIONS_CHECK(2);
+                       OP(opcode);
+                       OP(ICMD_NOP);
+                       break;
+
+               case BC_dup2_x1:
+                       INSTRUCTIONS_CHECK(7);
+                       OP(opcode);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       break;
+
+               case BC_dup2_x2:
+                       INSTRUCTIONS_CHECK(9);
+                       OP(opcode);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       break;
+
+               case BC_swap:
+                       INSTRUCTIONS_CHECK(3);
+                       OP(opcode);
+                       OP(ICMD_NOP);
+                       OP(ICMD_NOP);
+                       break;
+
+               /* local variable access instructions *********************************/
+
+               case BC_iload:
+               case BC_fload:
+               case BC_aload:
+                       if (iswide == false) {
+                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
+                       }
+                       else {
+                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                               nextbc = bcindex + 3;
+                               iswide = false;
+                       }
+                       OP_LOAD_ONEWORD(opcode, i, opcode - BC_iload);
+                       break;
+
+               case BC_lload:
+               case BC_dload:
+                       if (iswide == false) {
+                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
+                       }
+                       else {
+                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                               nextbc = bcindex + 3;
+                               iswide = false;
+                       }
+                       OP_LOAD_TWOWORD(opcode, i, opcode - BC_iload);
+                       break;
+
+               case BC_iload_0:
+               case BC_iload_1:
+               case BC_iload_2:
+               case BC_iload_3:
+                       OP_LOAD_ONEWORD(ICMD_ILOAD, opcode - BC_iload_0, TYPE_INT);
+                       break;
+
+               case BC_lload_0:
+               case BC_lload_1:
+               case BC_lload_2:
+               case BC_lload_3:
+                       OP_LOAD_TWOWORD(ICMD_LLOAD, opcode - BC_lload_0, TYPE_LNG);
+                       break;
+
+               case BC_fload_0:
+               case BC_fload_1:
+               case BC_fload_2:
+               case BC_fload_3:
+                       OP_LOAD_ONEWORD(ICMD_FLOAD, opcode - BC_fload_0, TYPE_FLT);
+                       break;
+
+               case BC_dload_0:
+               case BC_dload_1:
+               case BC_dload_2:
+               case BC_dload_3:
+                       OP_LOAD_TWOWORD(ICMD_DLOAD, opcode - BC_dload_0, TYPE_DBL);
+                       break;
+
+               case BC_aload_0:
+               case BC_aload_1:
+               case BC_aload_2:
+               case BC_aload_3:
+                       OP_LOAD_ONEWORD(ICMD_ALOAD, opcode - BC_aload_0, TYPE_ADR);
+                       break;
+
+               case BC_istore:
+               case BC_fstore:
+               case BC_astore:
+                       if (iswide == false) {
+                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
+                       }
+                       else {
+                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                               nextbc = bcindex + 3;
+                               iswide = false;
+                       }
+                       OP_STORE_ONEWORD(opcode, i, opcode - BC_istore);
+                       break;
+
+               case BC_lstore:
+               case BC_dstore:
+                       if (iswide == false) {
+                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
+                       }
+                       else {
+                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                               nextbc = bcindex + 3;
+                               iswide = false;
+                       }
+                       OP_STORE_TWOWORD(opcode, i, opcode - BC_istore);
+                       break;
+
+               case BC_istore_0:
+               case BC_istore_1:
+               case BC_istore_2:
+               case BC_istore_3:
+                       OP_STORE_ONEWORD(ICMD_ISTORE, opcode - BC_istore_0, TYPE_INT);
+                       break;
+
+               case BC_lstore_0:
+               case BC_lstore_1:
+               case BC_lstore_2:
+               case BC_lstore_3:
+                       OP_STORE_TWOWORD(ICMD_LSTORE, opcode - BC_lstore_0, TYPE_LNG);
+                       break;
+
+               case BC_fstore_0:
+               case BC_fstore_1:
+               case BC_fstore_2:
+               case BC_fstore_3:
+                       OP_STORE_ONEWORD(ICMD_FSTORE, opcode - BC_fstore_0, TYPE_FLT);
+                       break;
+
+               case BC_dstore_0:
+               case BC_dstore_1:
+               case BC_dstore_2:
+               case BC_dstore_3:
+                       OP_STORE_TWOWORD(ICMD_DSTORE, opcode - BC_dstore_0, TYPE_DBL);
+                       break;
+
+               case BC_astore_0:
+               case BC_astore_1:
+               case BC_astore_2:
+               case BC_astore_3:
+                       OP_STORE_ONEWORD(ICMD_ASTORE, opcode - BC_astore_0, TYPE_ADR);
+                       break;
+
+               case BC_iinc:
+                       {
+                               int v;
+
+                               if (iswide == false) {
+                                       i = SUCK_BE_U1(m->jcode + bcindex + 1);
+                                       v = SUCK_BE_S1(m->jcode + bcindex + 2);
+                               }
+                               else {
+                                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                                       v = SUCK_BE_S2(m->jcode + bcindex + 3);
+                                       nextbc = bcindex + 5;
+                                       iswide = false;
+                               }
+                               INDEX_ONEWORD(i);
+                               LOCALTYPE_USED(i, TYPE_INT);
+                               OP_LOCALINDEX_I(opcode, i, v);
+                       }
+                       break;
+
+               /* wider index for loading, storing and incrementing ******************/
+
+               case BC_wide:
+                       bcindex++;
+                       iswide = true;
+                       goto fetch_opcode;
+
+               /* managing arrays ****************************************************/
+
+               case BC_newarray:
+                       switch (SUCK_BE_S1(m->jcode + bcindex + 1)) {
+                       case 4:
+                               bte = builtintable_get_internal(BUILTIN_newarray_boolean);
+                               break;
+                       case 5:
+                               bte = builtintable_get_internal(BUILTIN_newarray_char);
+                               break;
+                       case 6:
+                               bte = builtintable_get_internal(BUILTIN_newarray_float);
+                               break;
+                       case 7:
+                               bte = builtintable_get_internal(BUILTIN_newarray_double);
+                               break;
+                       case 8:
+                               bte = builtintable_get_internal(BUILTIN_newarray_byte);
+                               break;
+                       case 9:
+                               bte = builtintable_get_internal(BUILTIN_newarray_short);
+                               break;
+                       case 10:
+                               bte = builtintable_get_internal(BUILTIN_newarray_int);
+                               break;
+                       case 11:
+                               bte = builtintable_get_internal(BUILTIN_newarray_long);
+                               break;
+#if defined(ENABLE_VERIFIER)
+                       default:
+                               exceptions_throw_verifyerror(m, "Invalid array-type to create");
+                               return false;
+#endif
+                       }
+                       OP_BUILTIN_CHECK_EXCEPTION(bte);
+                       break;
+
+               case BC_anewarray:
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       compr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
+                       if (compr == NULL)
+                               return false;
+
+                       if (!(cr = class_get_classref_multiarray_of(1, compr)))
+                               return false;
+
+                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+                               return false;
+
+                       INSTRUCTIONS_CHECK(2);
+                       OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
+                       bte = builtintable_get_internal(BUILTIN_newarray);
+                       OP_BUILTIN_CHECK_EXCEPTION(bte);
+                       s_count++;
+                       break;
+
+               case BC_multianewarray:
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       j = SUCK_BE_U1(m->jcode + bcindex + 3);
+  
+                       cr = (constant_classref *) class_getconstant(m->clazz, i, CONSTANT_Class);
+                       if (cr == NULL)
+                               return false;
+  
+                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+                               return false;
+  
+                       /* if unresolved, c == NULL */
+  
+                       iptr->s1.argcount = j;
+                       OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, INS_FLAG_CHECK);
+                       code_unflag_leafmethod(code);
+                       break;
+
+               /* control flow instructions ******************************************/
+
+               case BC_ifeq:
+               case BC_iflt:
+               case BC_ifle:
+               case BC_ifne:
+               case BC_ifgt:
+               case BC_ifge:
+               case BC_ifnull:
+               case BC_ifnonnull:
+               case BC_if_icmpeq:
+               case BC_if_icmpne:
+               case BC_if_icmplt:
+               case BC_if_icmpgt:
+               case BC_if_icmple:
+               case BC_if_icmpge:
+               case BC_if_acmpeq:
+               case BC_if_acmpne:
+               case BC_goto:
+                       i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
+                       CHECK_BYTECODE_INDEX(i);
+                       MARK_BASICBLOCK(&pd, i);
+                       blockend = true;
+                       OP_INSINDEX(opcode, i);
+                       break;
+
+               case BC_goto_w:
+                       i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
+                       CHECK_BYTECODE_INDEX(i);
+                       MARK_BASICBLOCK(&pd, i);
+                       blockend = true;
+                       OP_INSINDEX(ICMD_GOTO, i);
+                       break;
+
+               case BC_jsr:
+                       i = bcindex + SUCK_BE_S2(m->jcode + bcindex + 1);
+jsr_tail:
+                       CHECK_BYTECODE_INDEX(i);
+                       MARK_BASICBLOCK(&pd, i);
+                       blockend = true;
+                       OP_PREPARE_ZEROFLAGS(BC_jsr);
+                       iptr->sx.s23.s3.jsrtarget.insindex = i;
+                       PINC;
+                       break;
+
+               case BC_jsr_w:
+                       i = bcindex + SUCK_BE_S4(m->jcode + bcindex + 1);
+                       goto jsr_tail;
+
+               case BC_ret:
+                       if (iswide == false) {
+                               i = SUCK_BE_U1(m->jcode + bcindex + 1);
+                       }
+                       else {
+                               i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                               nextbc = bcindex + 3;
+                               iswide = false;
+                       }
+                       blockend = true;
+
+                       OP_LOAD_ONEWORD(opcode, i, TYPE_ADR);
+                       break;
+
+               case BC_ireturn:
+               case BC_lreturn:
+               case BC_freturn:
+               case BC_dreturn:
+               case BC_areturn:
+               case BC_return:
+                       blockend = true;
+                       /* XXX ARETURN will need a flag in the typechecker */
+                       OP(opcode);
+                       break;
+
+               case BC_athrow:
+                       blockend = true;
+                       /* XXX ATHROW will need a flag in the typechecker */
+                       OP(opcode);
+                       break;
+
+
+               /* table jumps ********************************************************/
+
+               case BC_lookupswitch:
+                       {
+                               s4 num, j;
+                               lookup_target_t *lookup;
+#if defined(ENABLE_VERIFIER)
+                               s4 prevvalue = 0;
+#endif
+                               blockend = true;
+                               nextbc = MEMORY_ALIGN((bcindex + 1), 4);
+
+                               CHECK_END_OF_BYTECODE(nextbc + 8);
+
+                               OP_PREPARE_ZEROFLAGS(opcode);
+
+                               /* default target */
+
+                               j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
+                               iptr->sx.s23.s3.lookupdefault.insindex = j;
+                               nextbc += 4;
+                               CHECK_BYTECODE_INDEX(j);
+                               MARK_BASICBLOCK(&pd, j);
+
+                               /* number of pairs */
+
+                               num = SUCK_BE_U4(m->jcode + nextbc);
+                               iptr->sx.s23.s2.lookupcount = num;
+                               nextbc += 4;
+
+                               /* allocate the intermediate code table */
+
+                               lookup = (lookup_target_t*) DumpMemory::allocate(sizeof(lookup_target_t) * num);
+                               iptr->dst.lookup = lookup;
+
+                               /* iterate over the lookup table */
+
+                               CHECK_END_OF_BYTECODE(nextbc + 8 * num);
+
+                               for (i = 0; i < num; i++) {
+                                       /* value */
+
+                                       j = SUCK_BE_S4(m->jcode + nextbc);
+                                       lookup->value = j;
+
+                                       nextbc += 4;
+
+#if defined(ENABLE_VERIFIER)
+                                       /* check if the lookup table is sorted correctly */
+
+                                       if (i && (j <= prevvalue)) {
+                                               exceptions_throw_verifyerror(m, "Unsorted lookup switch");
+                                               return false;
+                                       }
+                                       prevvalue = j;
+#endif
+                                       /* target */
+
+                                       j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
+                                       lookup->target.insindex = j;
+                                       lookup++;
+                                       nextbc += 4;
+                                       CHECK_BYTECODE_INDEX(j);
+                                       MARK_BASICBLOCK(&pd, j);
+                               }
+
+                               PINC;
+                               break;
+                       }
+
+               case BC_tableswitch:
+                       {
+                               s4 num, j;
+                               s4 deftarget;
+                               branch_target_t *table;
+
+                               blockend = true;
+                               nextbc = MEMORY_ALIGN((bcindex + 1), 4);
+
+                               CHECK_END_OF_BYTECODE(nextbc + 12);
+
+                               OP_PREPARE_ZEROFLAGS(opcode);
+
+                               /* default target */
+
+                               deftarget = bcindex + SUCK_BE_S4(m->jcode + nextbc);
+                               nextbc += 4;
+                               CHECK_BYTECODE_INDEX(deftarget);
+                               MARK_BASICBLOCK(&pd, deftarget);
+
+                               /* lower bound */
+
+                               j = SUCK_BE_S4(m->jcode + nextbc);
+                               iptr->sx.s23.s2.tablelow = j;
+                               nextbc += 4;
+
+                               /* upper bound */
+
+                               num = SUCK_BE_S4(m->jcode + nextbc);
+                               iptr->sx.s23.s3.tablehigh = num;
+                               nextbc += 4;
+
+                               /* calculate the number of table entries */
+
+                               num = num - j + 1;
+
+#if defined(ENABLE_VERIFIER)
+                               if (num < 1) {
+                                       exceptions_throw_verifyerror(m,
+                                                       "invalid TABLESWITCH: upper bound < lower bound");
+                                       return false;
+                               }
+#endif
+                               /* create the intermediate code table */
+                               /* the first entry is the default target */
+
+                               table = (branch_target_t*) DumpMemory::allocate(sizeof(branch_target_t) * (1 + num));
+                               iptr->dst.table = table;
+                               (table++)->insindex = deftarget;
+
+                               /* iterate over the target table */
+
+                               CHECK_END_OF_BYTECODE(nextbc + 4 * num);
+
+                               for (i = 0; i < num; i++) {
+                                       j = bcindex + SUCK_BE_S4(m->jcode + nextbc);
+                                       (table++)->insindex = j;
+                                       nextbc += 4;
+                                       CHECK_BYTECODE_INDEX(j);
+                                       MARK_BASICBLOCK(&pd, j);
+                               }
+
+                               PINC;
+                               break;
+                       }
+
+
+               /* load and store of object fields ************************************/
+
+               case BC_aastore:
+                       OP(opcode);
+                       code_unflag_leafmethod(code);
+                       break;
+
+               case BC_getstatic:
+               case BC_putstatic:
+               case BC_getfield:
+               case BC_putfield:
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_Fieldref);
+
+                       if (fmi == NULL)
+                               return false;
+
+                       OP_PREPARE_ZEROFLAGS(opcode);
+                       iptr->sx.s23.s3.fmiref = fmi;
+
+                       /* only with -noverify, otherwise the typechecker does this */
+
+#if defined(ENABLE_VERIFIER)
+                       if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
+#endif
+                               result = resolve_field_lazy(m, fmi);
+
+                               if (result == resolveFailed)
+                                       return false;
+
+                               if (result != resolveSucceeded) {
+                                       uf = resolve_create_unresolved_field(m->clazz, m, iptr);
+
+                                       if (uf == NULL)
+                                               return false;
+
+                                       /* store the unresolved_field pointer */
+
+                                       iptr->sx.s23.s3.uf = uf;
+                                       iptr->flags.bits |= INS_FLAG_UNRESOLVED;
+                               }
+#if defined(ENABLE_VERIFIER)
+                       }
+#endif
+                       PINC;
+                       break;
+
+
+               /* method invocation **************************************************/
+
+               case BC_invokestatic:
+                       OP_PREPARE_ZEROFLAGS(opcode);
+
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_Methodref);
+
+                       if (fmi == NULL)
+                               return false;
+
+                       md = fmi->parseddesc.md;
+
+                       if (md->params == NULL)
+                               if (!descriptor_params_from_paramtypes(md, ACC_STATIC))
+                                       return false;
+
+                       goto invoke_method;
+
+               case BC_invokespecial:
+                       OP_PREPARE_FLAGS(opcode, INS_FLAG_CHECK);
+
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_Methodref);
+
+                       goto invoke_nonstatic_method;
+
+               case BC_invokeinterface:
+                       OP_PREPARE_ZEROFLAGS(opcode);
+
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_InterfaceMethodref);
+
+                       goto invoke_nonstatic_method;
+
+               case BC_invokevirtual:
+                       OP_PREPARE_ZEROFLAGS(opcode);
+
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       fmi = (constant_FMIref*) class_getconstant(m->clazz, i, CONSTANT_Methodref);
+
+invoke_nonstatic_method:
+                       if (fmi == NULL)
+                               return false;
+
+                       md = fmi->parseddesc.md;
+
+                       if (md->params == NULL)
+                               if (!descriptor_params_from_paramtypes(md, 0))
+                                       return false;
+
+invoke_method:
+                       code_unflag_leafmethod(code);
+
+                       iptr->sx.s23.s3.fmiref = fmi;
+
+                       /* only with -noverify, otherwise the typechecker does this */
+
+#if defined(ENABLE_VERIFIER)
+                       if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
+#endif
+                               result = resolve_method_lazy(m, fmi, 
+                                                                                        (opcode == BC_invokespecial));
+
+                               if (result == resolveFailed)
+                                       return false;
+
+                               if (result == resolveSucceeded) {
+                                       methodinfo *mi = iptr->sx.s23.s3.fmiref->p.method;
+
+                                       /* if this call is monomorphic, turn it into an
+                                          INVOKESPECIAL */
+
+                                       assert(IS_FMIREF_RESOLVED(iptr->sx.s23.s3.fmiref));
+
+                                       if ((iptr->opc == ICMD_INVOKEVIRTUAL)
+                                               && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
+                                       {
+                                               iptr->opc         = ICMD_INVOKESPECIAL;
+                                               iptr->flags.bits |= INS_FLAG_CHECK;
+                                       }
+                               }
+                               else {
+                                       um = resolve_create_unresolved_method(m->clazz, m, fmi,
+                                                       (opcode == BC_invokestatic),
+                                                       (opcode == BC_invokespecial));
+
+                                       if (um == NULL)
+                                               return false;
+
+                                       /* store the unresolved_method pointer */
+
+                                       iptr->sx.s23.s3.um = um;
+                                       iptr->flags.bits |= INS_FLAG_UNRESOLVED;
+                               }
+#if defined(ENABLE_VERIFIER)
+                       }
+#endif
+                       PINC;
+                       break;
+
+               /* instructions taking class arguments ********************************/
+
+               case BC_new:
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       cr = (constant_classref*) class_getconstant(m->clazz, i, CONSTANT_Class);
+
+                       if (cr == NULL)
+                               return false;
+
+                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+                               return false;
+
+                       INSTRUCTIONS_CHECK(2);
+                       OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
+                       bte = builtintable_get_internal(BUILTIN_new);
+                       OP_BUILTIN_CHECK_EXCEPTION(bte);
+                       s_count++;
+                       break;
+
+               case BC_checkcast:
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       cr = (constant_classref*) class_getconstant(m->clazz, i, CONSTANT_Class);
+
+                       if (cr == NULL)
+                               return false;
+
+                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+                               return false;
+
+                       if (cr->name->text[0] == '[') {
+                               /* array type cast-check */
+                               flags = INS_FLAG_CHECK | INS_FLAG_ARRAY;
+                               code_unflag_leafmethod(code);
+                       }
+                       else {
+                               /* object type cast-check */
+                               flags = INS_FLAG_CHECK;
+                       }
+                       OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, flags);
+                       break;
+
+               case BC_instanceof:
+                       i = SUCK_BE_U2(m->jcode + bcindex + 1);
+                       cr = (constant_classref*) class_getconstant(m->clazz, i, CONSTANT_Class);
+
+                       if (cr == NULL)
+                               return false;
+
+                       if (!resolve_classref(m, cr, resolveLazy, true, true, &c))
+                               return false;
+
+                       if (cr->name->text[0] == '[') {
+                               /* array type cast-check */
+                               INSTRUCTIONS_CHECK(2);
+                               OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr);
+                               bte = builtintable_get_internal(BUILTIN_arrayinstanceof);
+                               OP_BUILTIN_NO_EXCEPTION(bte);
+                               s_count++;
+                       }
+                       else {
+                               /* object type cast-check */
+                               OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, 0 /* flags*/);
+                       }
+                       break;
+
+               /* synchronization instructions ***************************************/
+
+               case BC_monitorenter:
+#if defined(ENABLE_THREADS)
+                       if (checksync) {
+                               bte = builtintable_get_internal(LOCK_monitor_enter);
+                               OP_BUILTIN_CHECK_EXCEPTION(bte);
+                       }
+                       else
+#endif
+                       {
+                               OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+                               OP(ICMD_POP);
+                       }
+                       break;
+
+               case BC_monitorexit:
+#if defined(ENABLE_THREADS)
+                       if (checksync) {
+                               bte = builtintable_get_internal(LOCK_monitor_exit);
+                               OP_BUILTIN_CHECK_EXCEPTION(bte);
+                       }
+                       else
+#endif
+                       {
+                               OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+                               OP(ICMD_POP);
+                       }
+                       break;
+
+               /* arithmetic instructions that may become builtin functions **********/
+
+               case BC_idiv:
+#if !SUPPORT_DIVISION
+                       bte = builtintable_get_internal(BUILTIN_idiv);
+                       OP_BUILTIN_ARITHMETIC(opcode, bte);
+#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+                       OP(opcode);
+# else
+                       OP_CHECK_EXCEPTION(opcode);
+# endif
+#endif
+                       break;
+
+               case BC_irem:
+#if !SUPPORT_DIVISION
+                       bte = builtintable_get_internal(BUILTIN_irem);
+                       OP_BUILTIN_ARITHMETIC(opcode, bte);
+#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+                       OP(opcode);
+# else
+                       OP_CHECK_EXCEPTION(opcode);
+# endif
+#endif
+                       break;
+
+               case BC_ldiv:
+#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
+                       bte = builtintable_get_internal(BUILTIN_ldiv);
+                       OP_BUILTIN_ARITHMETIC(opcode, bte);
+#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+                       OP(opcode);
+# else
+                       OP_CHECK_EXCEPTION(opcode);
+# endif
+#endif
+                       break;
+
+               case BC_lrem:
+#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
+                       bte = builtintable_get_internal(BUILTIN_lrem);
+                       OP_BUILTIN_ARITHMETIC(opcode, bte);
+#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
+                       OP(opcode);
+# else
+                       OP_CHECK_EXCEPTION(opcode);
+# endif
+#endif
+                       break;
+
+               case BC_frem:
+#if defined(__I386__)
+                       OP(opcode);
+#else
+                       bte = builtintable_get_internal(BUILTIN_frem);
+                       OP_BUILTIN_NO_EXCEPTION(bte);
+#endif
+                       break;
+
+               case BC_drem:
+#if defined(__I386__)
+                       OP(opcode);
+#else
+                       bte = builtintable_get_internal(BUILTIN_drem);
+                       OP_BUILTIN_NO_EXCEPTION(bte);
+#endif
+                       break;
+
+               case BC_f2i:
+#if defined(__ALPHA__)
+                       bte = builtintable_get_internal(BUILTIN_f2i);
+                       OP_BUILTIN_NO_EXCEPTION(bte);
+#else
+                       OP(opcode);
+#endif
+                       break;
+
+               case BC_f2l:
+#if defined(__ALPHA__)
+                       bte = builtintable_get_internal(BUILTIN_f2l);
+                       OP_BUILTIN_NO_EXCEPTION(bte);
+#else
+                       OP(opcode);
+#endif
+                       break;
+
+               case BC_d2i:
+#if defined(__ALPHA__)
+                       bte = builtintable_get_internal(BUILTIN_d2i);
+                       OP_BUILTIN_NO_EXCEPTION(bte);
+#else
+                       OP(opcode);
+#endif
+                       break;
+
+               case BC_d2l:
+#if defined(__ALPHA__)
+                       bte = builtintable_get_internal(BUILTIN_d2l);
+                       OP_BUILTIN_NO_EXCEPTION(bte);
+#else
+                       OP(opcode);
+#endif
+                       break;
+
+
+               /* invalid opcodes ****************************************************/
+
+                       /* check for invalid opcodes if the verifier is enabled */
+#if defined(ENABLE_VERIFIER)
+               case BC_breakpoint:
+                       exceptions_throw_verifyerror(m, "Quick instructions shouldn't appear, yet.");
+                       return false;
+
+
+               /* Unused opcodes ************************************************** */
+
+               case 186:
+               case 203:
+               case 204:
+               case 205:
+               case 206:
+               case 207:
+               case 208:
+               case 209:
+               case 210:
+               case 211:
+               case 212:
+               case 213:
+               case 214:
+               case 215:
+               case 216:
+               case 217:
+               case 218:
+               case 219:
+               case 220:
+               case 221:
+               case 222:
+               case 223:
+               case 224:
+               case 225:
+               case 226:
+               case 227:
+               case 228:
+               case 229:
+               case 230:
+               case 231:
+               case 232:
+               case 233:
+               case 234:
+               case 235:
+               case 236:
+               case 237:
+               case 238:
+               case 239:
+               case 240:
+               case 241:
+               case 242:
+               case 243:
+               case 244:
+               case 245:
+               case 246:
+               case 247:
+               case 248:
+               case 249:
+               case 250:
+               case 251:
+               case 252:
+               case 253:
+               case 254:
+               case 255:
+                       exceptions_throw_verifyerror(m, "Illegal opcode %d at instr %d\n",
+                                                                                opcode, ircount);
+                       return false;
+                       break;
+#endif /* defined(ENABLE_VERIFIER) */
+
+               /* opcodes that don't require translation *****************************/
+
+               default:
+                       /* Straight-forward translation to HIR. */
+                       OP(opcode);
+                       break;
+
+               } /* end switch */
+
+               /* verifier checks ****************************************************/
+
+#if defined(ENABLE_VERIFIER)
+               /* If WIDE was used correctly, iswide should have been reset by now. */
+               if (iswide) {
+                       exceptions_throw_verifyerror(m,
+                                       "Illegal instruction: WIDE before incompatible opcode");
+                       return false;
+               }
+#endif /* defined(ENABLE_VERIFIER) */
+
+       } /* end for */
+
+       if (JITDATA_HAS_FLAG_REORDER(jd)) {
+               /* add a NOP to the last basic block */
+
+               INSTRUCTIONS_CHECK(1);
+               OP(ICMD_NOP);
+       }
+
+       /*** END OF LOOP **********************************************************/
+
+       /* assert that we did not write more ICMDs than allocated */
+
+       assert(ircount <= pd.instructionslength);
+       assert(ircount == (iptr - pd.instructions));
+
+       /*** verifier checks ******************************************************/
+
+#if defined(ENABLE_VERIFIER)
+       if (bcindex != m->jcodelength) {
+               exceptions_throw_verifyerror(m,
+                               "Command-sequence crosses code-boundary");
+               return false;
+       }
+
+       if (!blockend) {
+               exceptions_throw_verifyerror(m, "Falling off the end of the code");
+               return false;
+       }
+#endif /* defined(ENABLE_VERIFIER) */
+
+       /*** setup the methodinfo, allocate stack and basic blocks ****************/
+
+       /* identify basic blocks */
+
+       /* check if first instruction is a branch target */
+
+       if (pd.basicblockstart[0] == 1) {
+               jd->branchtoentry = true;
+       }
+       else {
+               /* first instruction always starts a basic block */
+
+               iptr = pd.instructions;
+
+               iptr->flags.bits |= INS_FLAG_BASICBLOCK;
+       }
+
+       /* Iterate over all bytecode instructions and set missing
+          basic-block starts in IR instructions. */
+
+       for (bcindex = 0; bcindex < m->jcodelength; bcindex++) {
+               /* Does the current bytecode instruction start a basic
+                  block? */
+
+               if (pd.basicblockstart[bcindex] == 1) {
+#if defined(ENABLE_VERIFIER)
+                       /* Check if this bytecode basic-block start at the
+                          beginning of a bytecode instruction. */
+
+                       if (pd.bytecodestart[bcindex] == 0) {
+                               exceptions_throw_verifyerror(m,
+                                                                                "Branch into middle of instruction");
+                               return false;
+                       }
+#endif
+
+                       /* Get the IR instruction mapped to the bytecode
+                          instruction and set the basic block flag. */
+
+                       irindex = pd.bytecodemap[bcindex];
+                       iptr    = pd.instructions + irindex;
+
+                       iptr->flags.bits |= INS_FLAG_BASICBLOCK;
+               }
+       }
+
+       /* IR instruction index to basic-block index mapping */
+
+       pd.instructionmap = (s4*) DumpMemory::allocate(sizeof(s4) * ircount);
+       MZERO(pd.instructionmap, s4, ircount);
+
+       /* Iterate over all IR instructions and count the basic blocks. */
+
+       iptr = pd.instructions;
+
+       bbcount = 0;
+
+       for (i = 0; i < ircount; i++, iptr++) {
+               if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
+                       /* store the basic-block number in the IR instruction
+                          map */
+
+                       pd.instructionmap[i] = bbcount;
+
+                       /* post-increment the basic-block count */
+
+                       bbcount++;
+               }
+       }
+
+       /* Allocate basic block array (one more for end ipc). */
+
+       jd->basicblocks = (basicblock*) DumpMemory::allocate(sizeof(basicblock) * (bbcount + 1));
+       MZERO(jd->basicblocks, basicblock, bbcount + 1);
+
+       /* Now iterate again over all IR instructions and initialize the
+          basic block structures and, in the same loop, resolve the
+          branch-target instruction indices to basic blocks. */
+
+       iptr = pd.instructions;
+       bptr = jd->basicblocks;
+
+       bbcount = 0;
+
+       for (i = 0; i < ircount; i++, iptr++) {
+               /* check for basic block */
+
+               if (INSTRUCTION_STARTS_BASICBLOCK(iptr)) {
+                       /* intialize the basic block */
+
+                       BASICBLOCK_INIT(bptr, m);
+
+                       bptr->iinstr = iptr;
+
+                       if (bbcount > 0) {
+                               bptr[-1].icount = bptr->iinstr - bptr[-1].iinstr;
+                       }
+
+                       /* bptr->icount is set when the next block is allocated */
+
+                       bptr->nr = bbcount++;
+                       bptr++;
+                       bptr[-1].next = bptr;
+               }
+
+               /* resolve instruction indices to basic blocks */
+
+               switch (iptr->opc) {
+               case ICMD_IFEQ:
+               case ICMD_IFLT:
+               case ICMD_IFLE:
+               case ICMD_IFNE:
+               case ICMD_IFGT:
+               case ICMD_IFGE:
+               case ICMD_IFNULL:
+               case ICMD_IFNONNULL:
+               case ICMD_IF_ICMPEQ:
+               case ICMD_IF_ICMPNE:
+               case ICMD_IF_ICMPLT:
+               case ICMD_IF_ICMPGT:
+               case ICMD_IF_ICMPLE:
+               case ICMD_IF_ICMPGE:
+               case ICMD_IF_ACMPEQ:
+               case ICMD_IF_ACMPNE:
+               case ICMD_GOTO:
+                       BYTECODEINDEX_TO_BASICBLOCK(iptr->dst);
+                       break;
+
+               case ICMD_JSR:
+                       BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.jsrtarget);
+                       break;
+
+               case ICMD_TABLESWITCH:
+                       table = iptr->dst.table;
+
+                       BYTECODEINDEX_TO_BASICBLOCK(*table);
+                       table++;
+
+                       j = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1;
+
+                       while (--j >= 0) {
+                               BYTECODEINDEX_TO_BASICBLOCK(*table);
+                               table++;
+                       }
+                       break;
+
+               case ICMD_LOOKUPSWITCH:
+                       BYTECODEINDEX_TO_BASICBLOCK(iptr->sx.s23.s3.lookupdefault);
+
+                       lookup = iptr->dst.lookup;
+
+                       j = iptr->sx.s23.s2.lookupcount;
+
+                       while (--j >= 0) {
+                               BYTECODEINDEX_TO_BASICBLOCK(lookup->target);
+                               lookup++;
+                       }
+                       break;
+               }
+       }
+
+       /* set instruction count of last real block */
+
+       if (bbcount > 0) {
+               bptr[-1].icount = (pd.instructions + ircount) - bptr[-1].iinstr;
+       }
+
+       /* allocate additional block at end */
+
+       BASICBLOCK_INIT(bptr, m);
+       bptr->nr = bbcount;
+
+       /* set basicblock pointers in exception table */
+
+       if (!parse_resolve_exception_table(jd, &pd))
+               return false;
+
+       /* store the local map */
+
+       jd->local_map = local_map;
+
+       /* calculate local variable renaming */
+
+       {
+               s4 nlocals = 0;
+               s4 i;
+               s4 t;
+               s4 varindex;
+               s4 *mapptr;
+               s4 *reversemap;
+
+               mapptr = local_map;
+
+               /* iterate over local_map[0..m->maxlocals*5-1] and allocate a unique */
+               /* variable index for each _used_ (javaindex,type) pair.             */
+               /* (local_map[javaindex*5+type] = cacaoindex)                        */
+               /* Unused (javaindex,type) pairs are marked with UNUSED.             */
+
+               for (i = 0; i < (m->maxlocals * 5); i++, mapptr++) {
+                       if (*mapptr)
+                               *mapptr = nlocals++;
+                       else
+                               *mapptr = UNUSED;
+               }
+
+               jd->localcount = nlocals;
+
+               /* calculate the (maximum) number of variables needed */
+
+               jd->varcount = 
+                         nlocals                                      /* local variables */
+                       + bbcount * m->maxstack                                 /* invars */
+                       + s_count;         /* variables created within blocks (non-invar) */
+
+               /* reserve the first indices for local variables */
+
+               jd->vartop = nlocals;
+
+               /* reserve extra variables needed by stack analyse */
+
+               jd->varcount += STACK_EXTRA_VARS;
+               jd->vartop   += STACK_EXTRA_VARS;
+
+               /* The verifier needs space for saving invars in some cases and */
+               /* extra variables.                                             */
+
+#if defined(ENABLE_VERIFIER)
+               jd->varcount += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
+               jd->vartop   += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
+#endif
+               /* allocate and initialize the variable array */
+
+               jd->var = (varinfo*) DumpMemory::allocate(sizeof(varinfo) * jd->varcount);
+               MZERO(jd->var, varinfo, jd->varcount);
+
+               /* set types of all locals in jd->var */
+               /* and fill the reverselocalmap       */
+
+               reversemap = (s4*) DumpMemory::allocate(sizeof(s4) * nlocals);
+
+               for (i = 0; i < m->maxlocals; i++)
+                       for (t=0; t<5; t++) {
+                               varindex = local_map[5*i + t];
+                               if (varindex != UNUSED) {
+                                       VAR(varindex)->type = t;
+                                       reversemap[varindex] = i;
+                               }
+                       }
+
+               jd->reverselocalmap = reversemap;
+       }
+
+       /* assign local variables to method variables */
+
+       jd->instructions     = pd.instructions;
+       jd->instructioncount = ircount;
+       jd->basicblockcount  = bbcount;
+       jd->stackcount       = s_count + bbcount * m->maxstack; /* in-stacks */
+
+       /* allocate stack table */
+
+       jd->stack = (stackelement_t*) DumpMemory::allocate(sizeof(stackelement_t) * jd->stackcount);
+
+       /* everything's ok */
+
+       return true;
+
+       /*** goto labels for throwing verifier exceptions *************************/
+
+#if defined(ENABLE_VERIFIER)
+
+throw_unexpected_end_of_bytecode:
+       exceptions_throw_verifyerror(m, "Unexpected end of bytecode");
+       return false;
+
+throw_invalid_bytecode_index:
+       exceptions_throw_verifyerror(m, "Illegal target of branch instruction");
+       return false;
+
+throw_illegal_local_variable_number:
+       exceptions_throw_verifyerror(m, "Illegal local variable number");
+       return false;
+
+#endif /* ENABLE_VERIFIER */
+}
+
+#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/jit/parse.h b/src/vm/jit/parse.h
deleted file mode 100644 (file)
index b10d7da..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/* src/vm/jit/parse.h - parser header
-
-   Copyright (C) 1996-2005, 2006, 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 _PARSE_H
-#define _PARSE_H
-
-#include "config.h"
-#include "vm/types.h"
-
-#include "vm/global.h"
-#include "vm/jit/codegen-common.hpp"
-
-
-/* macros for verifier checks during parsing **********************************/
-
-#if defined(ENABLE_VERIFIER)
-
-/* We have to check local variables indices here because they are             */
-/* used in stack.c to index the locals array.                                 */
-
-#define INDEX_ONEWORD(num) \
-    do { \
-        if (((num) < 0) || ((num) >= m->maxlocals)) \
-            goto throw_illegal_local_variable_number; \
-    } while (0)
-
-#define INDEX_TWOWORD(num) \
-    do { \
-        if (((num) < 0) || (((num) + 1) >= m->maxlocals)) \
-            goto throw_illegal_local_variable_number; \
-    } while (0)
-
-/* CHECK_BYTECODE_INDEX(i) checks whether i is a valid bytecode index.        */
-/* The end of the bytecode (i == m->jcodelength) is considered valid.         */
-
-#define CHECK_BYTECODE_INDEX(i) \
-    do { \
-        if (((i) < 0) || ((i) >= m->jcodelength)) \
-                       goto throw_invalid_bytecode_index; \
-    } while (0)
-
-/* CHECK_BYTECODE_INDEX_EXCLUSIVE is used for the exclusive ends               */
-/* of exception handler ranges.                                                */
-#define CHECK_BYTECODE_INDEX_EXCLUSIVE(i) \
-    do { \
-        if ((i) < 0 || (i) > m->jcodelength) \
-                       goto throw_invalid_bytecode_index; \
-    } while (0)
-
-#else /* !defined(ENABLE_VERIFIER) */
-
-#define INDEX_ONEWORD(num)
-#define INDEX_TWOWORD(num)
-#define CHECK_BYTECODE_INDEX(i)
-#define CHECK_BYTECODE_INDEX_EXCLUSIVE(i)
-
-#endif /* defined(ENABLE_VERIFIER) */
-
-
-/* basic block generating macro ***********************************************/
-
-#define MARK_BASICBLOCK(pd, i)                                       \
-    do {                                                             \
-        (pd)->basicblockstart[(i)] = 1;                              \
-    } while (0)
-
-#define INSTRUCTIONS_CHECK(i)                                        \
-    if ((ircount + (i)) > pd.instructionslength)                     \
-        iptr = parse_realloc_instructions(&pd, ircount, (i))
-
-
-/* intermediate code generating macros ****************************************/
-
-/* These macros ALWAYS set the following fields of *iptr to valid values:     */
-/*     iptr->opc                                                              */
-/*     iptr->flags                                                            */
-/*     iptr->line                                                             */
-
-/* These macros do NOT touch the following fields of *iptr, unless a value is */
-/* given for them:                                                            */
-/*     iptr->s1                                                               */
-/*     iptr->sx                                                               */
-/*     iptr->dst                                                              */
-
-/* The _PREPARE macros omit the PINC, so you can set additional fields        */
-/* afterwards.                                                                */
-
-#define PINC                                                         \
-    iptr++; ircount++
-
-#define OP_PREPARE_FLAGS(o, f)                                       \
-    iptr->opc         = (o);                                         \
-    iptr->line        = currentline;                                 \
-    iptr->flags.bits |= (f) | (ircount << INS_FLAG_ID_SHIFT);
-
-#define OP_PREPARE_ZEROFLAGS(o)                                      \
-    OP_PREPARE_FLAGS(o, 0)
-
-#define OP_PREPARE(o)                                                \
-    OP_PREPARE_ZEROFLAGS(o)
-
-#define OP(o)                                                        \
-    OP_PREPARE_ZEROFLAGS(o);                                         \
-    PINC
-
-#define OP_CHECK_EXCEPTION(o)                                        \
-    OP_PREPARE_FLAGS(o, INS_FLAG_CHECK);                             \
-    PINC
-
-#define OP_LOADCONST_I(v)                                            \
-    OP_PREPARE_ZEROFLAGS(ICMD_ICONST);                               \
-    iptr->sx.val.i           = (v);                                  \
-    PINC
-
-#define OP_LOADCONST_L(v)                                            \
-    OP_PREPARE_ZEROFLAGS(ICMD_LCONST);                               \
-    iptr->sx.val.l           = (v);                                  \
-    PINC
-
-#define OP_LOADCONST_F(v)                                            \
-    OP_PREPARE_ZEROFLAGS(ICMD_FCONST);                               \
-    iptr->sx.val.f           = (v);                                  \
-    PINC
-
-#define OP_LOADCONST_D(v)                                            \
-    OP_PREPARE_ZEROFLAGS(ICMD_DCONST);                               \
-    iptr->sx.val.d           = (v);                                  \
-    PINC
-
-#define OP_LOADCONST_NULL()                                          \
-    OP_PREPARE_FLAGS(ICMD_ACONST, INS_FLAG_CHECK);                   \
-    iptr->sx.val.anyptr      = NULL;                                 \
-    PINC
-
-#define OP_LOADCONST_STRING(v)                                       \
-    OP_PREPARE_FLAGS(ICMD_ACONST, INS_FLAG_CHECK);                   \
-    iptr->sx.val.stringconst = (v);                                  \
-    PINC
-
-#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS(cl, cr, extraflags) \
-    OP_PREPARE(ICMD_ACONST);                                         \
-    if (cl) {                                                        \
-        iptr->sx.val.c.cls   = (cl);                                 \
-        iptr->flags.bits     |= INS_FLAG_CLASS | (extraflags);       \
-    }                                                                \
-    else {                                                           \
-        iptr->sx.val.c.ref   = (cr);                                 \
-        iptr->flags.bits     |= INS_FLAG_CLASS | INS_FLAG_UNRESOLVED \
-                             | (extraflags);                         \
-    }                                                                \
-    PINC
-
-#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr)              \
-    OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS((c), (cr), INS_FLAG_CHECK)
-
-#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr)            \
-    OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS((c), (cr), 0)
-
-#define OP_S3_CLASSINFO_OR_CLASSREF(o, c, cr, extraflags)            \
-    OP_PREPARE(o);                                                   \
-    if (c) {                                                         \
-        iptr->sx.s23.s3.c.cls= (c);                                  \
-        iptr->flags.bits     |= (extraflags);                        \
-    }                                                                \
-    else {                                                           \
-        iptr->sx.s23.s3.c.ref= (cr);                                 \
-        iptr->flags.bits     |= INS_FLAG_UNRESOLVED | (extraflags);  \
-    }                                                                \
-    PINC
-
-#define OP_INSINDEX(o, iindex)                                       \
-    OP_PREPARE_ZEROFLAGS(o);                                         \
-    iptr->dst.insindex       = (iindex);                             \
-    PINC
-
-# define OP_LOCALINDEX(o,index)                                      \
-    OP_PREPARE_ZEROFLAGS(o);                                         \
-    iptr->s1.varindex      = (index);                                \
-    PINC
-
-# define OP_LOCALINDEX_I(o,index,v)                                  \
-    OP_PREPARE_ZEROFLAGS(o);                                         \
-    iptr->s1.varindex      = (index);                                \
-    iptr->sx.val.i           = (v);                                  \
-    PINC
-
-# define LOCALTYPE_USED(index,type)                                  \
-    do {                                                             \
-        local_map[(index) * 5 + (type)] = 1;                         \
-    } while (0)
-
-#define OP_LOAD_ONEWORD(o,index,type)                                \
-    do {                                                             \
-        INDEX_ONEWORD(index);                                        \
-        OP_LOCALINDEX(o,index);                                      \
-        LOCALTYPE_USED(index,type);                                  \
-    } while (0)
-
-#define OP_LOAD_TWOWORD(o,index,type)                                \
-    do {                                                             \
-        INDEX_TWOWORD(index);                                        \
-        OP_LOCALINDEX(o,index);                                      \
-        LOCALTYPE_USED(index,type);                                  \
-    } while (0)
-
-# define OP_STORE_ONEWORD(o,index,type)                              \
-    do {                                                             \
-        INDEX_ONEWORD(index);                                        \
-        OP_PREPARE_ZEROFLAGS(o);                                     \
-        iptr->dst.varindex = (index);                                \
-        LOCALTYPE_USED(index,type);                                  \
-        PINC;                                                        \
-    } while (0)
-
-# define OP_STORE_TWOWORD(o,index,type)                              \
-    do {                                                             \
-        INDEX_TWOWORD(index);                                        \
-        OP_PREPARE_ZEROFLAGS(o);                                     \
-        iptr->dst.varindex = (index);                                \
-        LOCALTYPE_USED(index,type);                                  \
-        PINC;                                                        \
-    } while (0)
-
-#define OP_BUILTIN_CHECK_EXCEPTION(bte)                              \
-    code_unflag_leafmethod(code);                                    \
-    OP_PREPARE_FLAGS(ICMD_BUILTIN, INS_FLAG_CHECK);                  \
-    iptr->sx.s23.s3.bte      = (bte);                                \
-    PINC
-
-#define OP_BUILTIN_NO_EXCEPTION(bte)                                 \
-    code_unflag_leafmethod(code);                                    \
-    OP_PREPARE_ZEROFLAGS(ICMD_BUILTIN);                              \
-    iptr->sx.s23.s3.bte      = (bte);                                \
-    PINC
-
-#define OP_BUILTIN_ARITHMETIC(opcode, bte)                           \
-    code_unflag_leafmethod(code);                                    \
-    OP_PREPARE_FLAGS(opcode, INS_FLAG_CHECK);                        \
-    iptr->sx.s23.s3.bte      = (bte);                                \
-    PINC
-
-/* CAUTION: You must set iptr->flags yourself when using this!                */
-#define OP_FMIREF_PREPARE(o, fmiref)                                 \
-    OP_PREPARE(o);                                                   \
-    iptr->sx.s23.s3.fmiref   = (fmiref);
-
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-bool parse(jitdata *jd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PARSE_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/jit/parse.hpp b/src/vm/jit/parse.hpp
new file mode 100644 (file)
index 0000000..b10d7da
--- /dev/null
@@ -0,0 +1,298 @@
+/* src/vm/jit/parse.h - parser header
+
+   Copyright (C) 1996-2005, 2006, 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 _PARSE_H
+#define _PARSE_H
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "vm/global.h"
+#include "vm/jit/codegen-common.hpp"
+
+
+/* macros for verifier checks during parsing **********************************/
+
+#if defined(ENABLE_VERIFIER)
+
+/* We have to check local variables indices here because they are             */
+/* used in stack.c to index the locals array.                                 */
+
+#define INDEX_ONEWORD(num) \
+    do { \
+        if (((num) < 0) || ((num) >= m->maxlocals)) \
+            goto throw_illegal_local_variable_number; \
+    } while (0)
+
+#define INDEX_TWOWORD(num) \
+    do { \
+        if (((num) < 0) || (((num) + 1) >= m->maxlocals)) \
+            goto throw_illegal_local_variable_number; \
+    } while (0)
+
+/* CHECK_BYTECODE_INDEX(i) checks whether i is a valid bytecode index.        */
+/* The end of the bytecode (i == m->jcodelength) is considered valid.         */
+
+#define CHECK_BYTECODE_INDEX(i) \
+    do { \
+        if (((i) < 0) || ((i) >= m->jcodelength)) \
+                       goto throw_invalid_bytecode_index; \
+    } while (0)
+
+/* CHECK_BYTECODE_INDEX_EXCLUSIVE is used for the exclusive ends               */
+/* of exception handler ranges.                                                */
+#define CHECK_BYTECODE_INDEX_EXCLUSIVE(i) \
+    do { \
+        if ((i) < 0 || (i) > m->jcodelength) \
+                       goto throw_invalid_bytecode_index; \
+    } while (0)
+
+#else /* !defined(ENABLE_VERIFIER) */
+
+#define INDEX_ONEWORD(num)
+#define INDEX_TWOWORD(num)
+#define CHECK_BYTECODE_INDEX(i)
+#define CHECK_BYTECODE_INDEX_EXCLUSIVE(i)
+
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/* basic block generating macro ***********************************************/
+
+#define MARK_BASICBLOCK(pd, i)                                       \
+    do {                                                             \
+        (pd)->basicblockstart[(i)] = 1;                              \
+    } while (0)
+
+#define INSTRUCTIONS_CHECK(i)                                        \
+    if ((ircount + (i)) > pd.instructionslength)                     \
+        iptr = parse_realloc_instructions(&pd, ircount, (i))
+
+
+/* intermediate code generating macros ****************************************/
+
+/* These macros ALWAYS set the following fields of *iptr to valid values:     */
+/*     iptr->opc                                                              */
+/*     iptr->flags                                                            */
+/*     iptr->line                                                             */
+
+/* These macros do NOT touch the following fields of *iptr, unless a value is */
+/* given for them:                                                            */
+/*     iptr->s1                                                               */
+/*     iptr->sx                                                               */
+/*     iptr->dst                                                              */
+
+/* The _PREPARE macros omit the PINC, so you can set additional fields        */
+/* afterwards.                                                                */
+
+#define PINC                                                         \
+    iptr++; ircount++
+
+#define OP_PREPARE_FLAGS(o, f)                                       \
+    iptr->opc         = (o);                                         \
+    iptr->line        = currentline;                                 \
+    iptr->flags.bits |= (f) | (ircount << INS_FLAG_ID_SHIFT);
+
+#define OP_PREPARE_ZEROFLAGS(o)                                      \
+    OP_PREPARE_FLAGS(o, 0)
+
+#define OP_PREPARE(o)                                                \
+    OP_PREPARE_ZEROFLAGS(o)
+
+#define OP(o)                                                        \
+    OP_PREPARE_ZEROFLAGS(o);                                         \
+    PINC
+
+#define OP_CHECK_EXCEPTION(o)                                        \
+    OP_PREPARE_FLAGS(o, INS_FLAG_CHECK);                             \
+    PINC
+
+#define OP_LOADCONST_I(v)                                            \
+    OP_PREPARE_ZEROFLAGS(ICMD_ICONST);                               \
+    iptr->sx.val.i           = (v);                                  \
+    PINC
+
+#define OP_LOADCONST_L(v)                                            \
+    OP_PREPARE_ZEROFLAGS(ICMD_LCONST);                               \
+    iptr->sx.val.l           = (v);                                  \
+    PINC
+
+#define OP_LOADCONST_F(v)                                            \
+    OP_PREPARE_ZEROFLAGS(ICMD_FCONST);                               \
+    iptr->sx.val.f           = (v);                                  \
+    PINC
+
+#define OP_LOADCONST_D(v)                                            \
+    OP_PREPARE_ZEROFLAGS(ICMD_DCONST);                               \
+    iptr->sx.val.d           = (v);                                  \
+    PINC
+
+#define OP_LOADCONST_NULL()                                          \
+    OP_PREPARE_FLAGS(ICMD_ACONST, INS_FLAG_CHECK);                   \
+    iptr->sx.val.anyptr      = NULL;                                 \
+    PINC
+
+#define OP_LOADCONST_STRING(v)                                       \
+    OP_PREPARE_FLAGS(ICMD_ACONST, INS_FLAG_CHECK);                   \
+    iptr->sx.val.stringconst = (v);                                  \
+    PINC
+
+#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS(cl, cr, extraflags) \
+    OP_PREPARE(ICMD_ACONST);                                         \
+    if (cl) {                                                        \
+        iptr->sx.val.c.cls   = (cl);                                 \
+        iptr->flags.bits     |= INS_FLAG_CLASS | (extraflags);       \
+    }                                                                \
+    else {                                                           \
+        iptr->sx.val.c.ref   = (cr);                                 \
+        iptr->flags.bits     |= INS_FLAG_CLASS | INS_FLAG_UNRESOLVED \
+                             | (extraflags);                         \
+    }                                                                \
+    PINC
+
+#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr)              \
+    OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS((c), (cr), INS_FLAG_CHECK)
+
+#define OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr)            \
+    OP_LOADCONST_CLASSINFO_OR_CLASSREF_FLAGS((c), (cr), 0)
+
+#define OP_S3_CLASSINFO_OR_CLASSREF(o, c, cr, extraflags)            \
+    OP_PREPARE(o);                                                   \
+    if (c) {                                                         \
+        iptr->sx.s23.s3.c.cls= (c);                                  \
+        iptr->flags.bits     |= (extraflags);                        \
+    }                                                                \
+    else {                                                           \
+        iptr->sx.s23.s3.c.ref= (cr);                                 \
+        iptr->flags.bits     |= INS_FLAG_UNRESOLVED | (extraflags);  \
+    }                                                                \
+    PINC
+
+#define OP_INSINDEX(o, iindex)                                       \
+    OP_PREPARE_ZEROFLAGS(o);                                         \
+    iptr->dst.insindex       = (iindex);                             \
+    PINC
+
+# define OP_LOCALINDEX(o,index)                                      \
+    OP_PREPARE_ZEROFLAGS(o);                                         \
+    iptr->s1.varindex      = (index);                                \
+    PINC
+
+# define OP_LOCALINDEX_I(o,index,v)                                  \
+    OP_PREPARE_ZEROFLAGS(o);                                         \
+    iptr->s1.varindex      = (index);                                \
+    iptr->sx.val.i           = (v);                                  \
+    PINC
+
+# define LOCALTYPE_USED(index,type)                                  \
+    do {                                                             \
+        local_map[(index) * 5 + (type)] = 1;                         \
+    } while (0)
+
+#define OP_LOAD_ONEWORD(o,index,type)                                \
+    do {                                                             \
+        INDEX_ONEWORD(index);                                        \
+        OP_LOCALINDEX(o,index);                                      \
+        LOCALTYPE_USED(index,type);                                  \
+    } while (0)
+
+#define OP_LOAD_TWOWORD(o,index,type)                                \
+    do {                                                             \
+        INDEX_TWOWORD(index);                                        \
+        OP_LOCALINDEX(o,index);                                      \
+        LOCALTYPE_USED(index,type);                                  \
+    } while (0)
+
+# define OP_STORE_ONEWORD(o,index,type)                              \
+    do {                                                             \
+        INDEX_ONEWORD(index);                                        \
+        OP_PREPARE_ZEROFLAGS(o);                                     \
+        iptr->dst.varindex = (index);                                \
+        LOCALTYPE_USED(index,type);                                  \
+        PINC;                                                        \
+    } while (0)
+
+# define OP_STORE_TWOWORD(o,index,type)                              \
+    do {                                                             \
+        INDEX_TWOWORD(index);                                        \
+        OP_PREPARE_ZEROFLAGS(o);                                     \
+        iptr->dst.varindex = (index);                                \
+        LOCALTYPE_USED(index,type);                                  \
+        PINC;                                                        \
+    } while (0)
+
+#define OP_BUILTIN_CHECK_EXCEPTION(bte)                              \
+    code_unflag_leafmethod(code);                                    \
+    OP_PREPARE_FLAGS(ICMD_BUILTIN, INS_FLAG_CHECK);                  \
+    iptr->sx.s23.s3.bte      = (bte);                                \
+    PINC
+
+#define OP_BUILTIN_NO_EXCEPTION(bte)                                 \
+    code_unflag_leafmethod(code);                                    \
+    OP_PREPARE_ZEROFLAGS(ICMD_BUILTIN);                              \
+    iptr->sx.s23.s3.bte      = (bte);                                \
+    PINC
+
+#define OP_BUILTIN_ARITHMETIC(opcode, bte)                           \
+    code_unflag_leafmethod(code);                                    \
+    OP_PREPARE_FLAGS(opcode, INS_FLAG_CHECK);                        \
+    iptr->sx.s23.s3.bte      = (bte);                                \
+    PINC
+
+/* CAUTION: You must set iptr->flags yourself when using this!                */
+#define OP_FMIREF_PREPARE(o, fmiref)                                 \
+    OP_PREPARE(o);                                                   \
+    iptr->sx.s23.s3.fmiref   = (fmiref);
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool parse(jitdata *jd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PARSE_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 c7431f8093f8e55f21936929a789a482a51a3352..dcfc0482e276bfe38417c7cbebd7ecc8ca58ab41 100644 (file)
@@ -59,7 +59,7 @@
 #include "vm/jit/jit.hpp"
 #include "vm/jit/linenumbertable.hpp"
 #include "vm/jit/methodheader.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/patcher-common.hpp"
 #include "vm/jit/reg.h"
 #include "vm/jit/replace.hpp"
index 68899b4eed91f0bd048674cd78691b49a7cbb961..35b7c48226739bd39e5160182c64d0b7c21880af 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "vm/jit/powerpc/darwin/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 
 #include "vm/jit/abi.h"
index df5af31dbfbdf1d354915418c61458a22a099666..1282c5ee5c6fde83a034834780843aeb6c21507d 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "vm/jit/powerpc/linux/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 
 #include "vm/jit/abi.h"
index aa9caeb424cc5dba210566c91949ef7d161a8b6b..36dd169c3798aa17a0164944a2f75d2b26f50927 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "vm/jit/powerpc/netbsd/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 
 #include "vm/jit/abi.h"
index 64855d6dd251ea2f17006d65f4b63c5df5890590..6de89aaf0b6c5c16d65127a5f882d02e4e68a968 100644 (file)
@@ -59,7 +59,7 @@
 #include "vm/jit/emit-common.hpp"
 #include "vm/jit/jit.hpp"
 #include "vm/jit/linenumbertable.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/patcher-common.hpp"
 #include "vm/jit/reg.h"
 #include "vm/jit/replace.hpp"
index 68f1ae5e768a8f47acb1eed3089f9ed0d2909d39..e77ff4806166704c44b50e9798bbd3ae402f3407 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "vm/jit/powerpc64/linux/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 
 #include "vm/jit/abi.h"
index 9dc637b3f12df8b3d866bc2f2a315cdb509f4d60..5235e1b119ea9356d388263f47c88e6b0e84dcc9 100644 (file)
@@ -38,7 +38,7 @@ typedef struct registerdata registerdata;
 #include "arch.h"
 
 #include "vm/jit/jit.hpp"
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
 
 
 /************************* pseudo variable structure **************************/
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 7db818cadc79711f99fd64de3a56a1a58bc99968..f69e661fb8f8a64fc5a4d8cccc5442923820b369 100644 (file)
@@ -61,7 +61,7 @@
 #include "vm/jit/jit.hpp"
 #include "vm/jit/linenumbertable.hpp"
 #include "vm/jit/methodheader.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/patcher-common.hpp"
 #include "vm/jit/reg.h"
 #include "vm/jit/replace.hpp"
index 95ad22ac5d0e1e6be847fa5f99c2d56d075a872f..474b7ff2ac0f0f07f0e5cbe0940483f16cdaf6ae 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "config.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 #include "vm/types.h"
 
index d4dad98c7c069427575e10ea835afc917db2e0b7..e0ba2a3cfaa9de1257e145af3606709e6216a40f 100644 (file)
@@ -45,7 +45,7 @@
 #include "vm/jit/show.hpp"
 #include "vm/jit/disass.h"
 #include "vm/jit/stack.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 
 #if defined(ENABLE_DEBUG_FILTER)
 # include <sys/types.h>
index dc0533c2f168d57ad763271470760dc948e16f50..b048fbe3272e933413752b0fe8aa8da7966f299d 100644 (file)
@@ -55,7 +55,7 @@
 #include "vm/jit/emit-common.hpp"
 #include "vm/jit/jit.hpp"
 #include "vm/jit/linenumbertable.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/patcher.h"
 #include "vm/jit/reg.h"
 #include "vm/jit/replace.hpp"
index cc12be598716a5abb965949cc178b629d7e566ff..edcf00a18208cd5bc9284aef8dc8eb688af65898 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "vm/jit/sparc64/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 
 #include "vm/jit/abi.h"
index 2420c649f79d1b71c6623dcc486eeffdc7692436..8c7ad97c3c9bab8c95dca5327998f05532f08eeb 100644 (file)
@@ -54,7 +54,7 @@
 #include "vm/jit/abi.h"
 #include "vm/jit/cfg.h"
 #include "vm/jit/codegen-common.hpp"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/show.hpp"
 
 #if defined(ENABLE_DISASSEMBLER)
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 8be3839e3a1ae3c916c7df1fd1c917bea5bbad69..c9e3a632e3992d2316c33b4977cb204970014417 100644 (file)
@@ -37,22 +37,22 @@ LIBS =
 noinst_LTLIBRARIES = libverify.la
 
 libverify_la_SOURCES = \
-       typecheck.c \
-       typecheck.h \
-       typecheck-common.c \
-       typecheck-common.h \
+       typecheck.cpp \
+       typecheck.hpp \
+       typecheck-common.cpp \
+       typecheck-common.hpp \
        typecheck-builtins.inc \
        typecheck-fields.inc \
        typecheck-invoke.inc \
        typecheck-multianewarray.inc \
-       typecheck-stackbased.c \
-       typecheck-typeinferer.c \
-       typecheck-typeinferer.h \
+       typecheck-stackbased.cpp \
+       typecheck-typeinferer.cpp \
+       typecheck-typeinferer.hpp \
        typecheck-stackbased-gen.inc \
        typecheck-variablesbased-gen.inc \
        typecheck-typeinferer-gen.inc \
-       typeinfo.c \
-       typeinfo.h
+       typeinfo.cpp \
+       typeinfo.hpp
 
 
 ## Local variables:
diff --git a/src/vm/jit/verify/icmds.c b/src/vm/jit/verify/icmds.c
deleted file mode 100644 (file)
index 65adf81..0000000
+++ /dev/null
@@ -1,779 +0,0 @@
-/* src/vm/jit/verify/icmds.c - ICMD-specific type checking code
-
-   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.
-
-*/
-
-#if 0 /* (needed for code examples in the following comment) */
-/******************************************************************************/
-/* This file contains ICMD-specific code for type checking and type
- * inference. It is an input file for the verifier generator
- * (src/vm/jit/verify/generate.pl). The verifier generator creates
- * code for three compiler passes:
- *     - stack-based type-infering verification
- *     - vasiables-based type-infering verification
- *     - type inference pass (no verification - used for optimizing compiler)
- *
- * The rest of this file must consist of "case" clauses starting in
- * the first column. Each clause can be marked with tags like this:
- *
- */          case ICMD_CONSTANT: /* {TAG, TAG, ...} */
-/*
- * This must be on one line. The following tags are defined:
- *     STACKBASED..........use this clause for the stack-based verifier
- *     VARIABLESBASED......use this clause for the variables-based verifier
- *     TYPEINFERER.........use this clause for the type inference pass
- *     ALL.................use for all passes
- *
- * If no tag is specified, {STACKBASED,VARIABLESBASED} is assumed.
- *
- * There are also tags that can be used inside a clause like this:
- *
- */          /* {TAG} */
-/*
- * The following tags are defined within clauses:
- *     RESULTNOW...........generate code for modelling the stack action
- *                         _before_ the user-defined code in the clause
- *                         (Default is to model the stack action afterwards.)
- *
- * The following macros are pre-defined:
- *
- *     TYPECHECK_STACKBASED.......iff compiling the stack-based verifier
- *     TYPECHECK_VARIABLESBASED...iff compiling the variables-based verifier
- *     TYPECHECK_TYPEINFERER......iff compiling the type inference pass
- *
-/******************************************************************************/
-#endif /* (end #if 0) */
-
-
-/* this marker is needed by generate.pl: */
-/* {START_OF_CODE} */
-
-       /****************************************/
-       /* MOVE/COPY                            */
-
-       /* We just need to copy the typeinfo */
-       /* for slots containing addresses.   */
-
-       /* (These are only used by the variables based verifier.) */
-
-case ICMD_MOVE: /* {VARIABLESBASED,TYPEINFERER} */
-case ICMD_COPY: /* {VARIABLESBASED,TYPEINFERER} */
-       TYPECHECK_COUNT(stat_ins_stack);
-       COPYTYPE(IPTR->s1, IPTR->dst);
-       DST->type = OP1->type;
-       break;
-
-       /****************************************/
-       /* LOADING ADDRESS FROM VARIABLE        */
-
-case ICMD_ALOAD: /* {ALL} */
-       TYPECHECK_COUNT(stat_ins_aload);
-
-#if !defined(TYPECHECK_TYPEINFERER)
-       /* loading a returnAddress is not allowed */
-       if (!TYPEDESC_IS_REFERENCE(*OP1)) {
-               VERIFY_ERROR("illegal instruction: ALOAD loading non-reference");
-       }
-#endif
-       TYPEINFO_COPY(OP1->typeinfo,DST->typeinfo);
-       break;
-
-       /****************************************/
-       /* STORING ADDRESS TO VARIABLE          */
-
-case ICMD_ASTORE: /* {ALL} */
-       TYPEINFO_COPY(OP1->typeinfo, DST->typeinfo);
-       break;
-
-       /****************************************/
-       /* LOADING ADDRESS FROM ARRAY           */
-
-case ICMD_AALOAD: /* {ALL} */
-#if !defined(TYPECHECK_TYPEINFERER)
-       if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(OP1->typeinfo))
-               VERIFY_ERROR("illegal instruction: AALOAD on non-reference array");
-#endif
-
-       if (!typeinfo_init_component(&OP1->typeinfo,&DST->typeinfo))
-               EXCEPTION;
-       break;
-
-       /****************************************/
-       /* FIELD ACCESS                         */
-
-case ICMD_PUTFIELD: /* {STACKBASED} */
-       CHECK_STACK_DEPTH(2);
-       if (!IS_CAT1(stack[0])) {
-               CHECK_STACK_DEPTH(3);
-               stack -= 1;
-       }
-       CHECK_STACK_TYPE(stack[-1], TYPE_ADR);
-       stack = typecheck_stackbased_verify_fieldaccess(STATE, stack-1, stack, stack-2);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_PUTSTATIC: /* {STACKBASED} */
-       CHECK_STACK_DEPTH(1);
-       if (!IS_CAT1(stack[0])) {
-               /* (stack depth >= 2 is guaranteed) */
-               stack -= 1;
-       }
-       stack = typecheck_stackbased_verify_fieldaccess(STATE, NULL, stack, stack-1);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_GETFIELD: /* {STACKBASED} */
-       CHECK_STACK_TYPE(stack[0], TYPE_ADR);
-       stack = typecheck_stackbased_verify_fieldaccess(STATE, stack, NULL, stack-1);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_GETSTATIC:      /* {STACKBASED} */
-       stack = typecheck_stackbased_verify_fieldaccess(STATE, NULL, NULL, stack);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_PUTFIELD:       /* {VARIABLESBASED} */
-       if (!handle_fieldaccess(state, VAROP(iptr->s1), VAROP(iptr->sx.s23.s2)))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_PUTSTATIC:      /* {VARIABLESBASED} */
-       if (!handle_fieldaccess(state, NULL, VAROP(iptr->s1)))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_PUTFIELDCONST:  /* {VARIABLESBASED} */
-       /* XXX this mess will go away with const operands */
-       INSTRUCTION_GET_FIELDREF(state->iptr, fieldref);
-       constvalue.type = fieldref->parseddesc.fd->type;
-       if (IS_ADR_TYPE(constvalue.type)) {
-               if (state->iptr->sx.val.anyptr) {
-                       classinfo *cc = (state->iptr->flags.bits & INS_FLAG_CLASS)
-                               ? class_java_lang_Class : class_java_lang_String;
-                       assert(cc);
-                       assert(cc->state & CLASS_LINKED);
-                       typeinfo_init_classinfo(&(constvalue.typeinfo), cc);
-               }
-               else {
-                       TYPEINFO_INIT_NULLTYPE(constvalue.typeinfo);
-               }
-       }
-       if (!handle_fieldaccess(state, VAROP(iptr->s1), &constvalue))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_PUTSTATICCONST: /* {VARIABLESBASED} */
-       /* XXX this mess will go away with const operands */
-       INSTRUCTION_GET_FIELDREF(state->iptr, fieldref);
-       constvalue.type = fieldref->parseddesc.fd->type;
-       if (IS_ADR_TYPE(constvalue.type)) {
-               if (state->iptr->sx.val.anyptr) {
-                       classinfo *cc = (state->iptr->flags.bits & INS_FLAG_CLASS)
-                               ? class_java_lang_Class : class_java_lang_String;
-                       assert(cc);
-                       assert(cc->state & CLASS_LINKED);
-                       typeinfo_init_classinfo(&(constvalue.typeinfo), cc);
-               }
-               else {
-                       TYPEINFO_INIT_NULLTYPE(constvalue.typeinfo);
-               }
-       }
-       if (!handle_fieldaccess(state, NULL, &constvalue))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_GETFIELD:       /* {VARIABLESBASED,TYPEINFERER} */
-       if (!handle_fieldaccess(state, VAROP(iptr->s1), NULL))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_GETSTATIC:      /* {VARIABLESBASED,TYPEINFERER} */
-       if (!handle_fieldaccess(state, NULL, NULL))
-               return false;
-       maythrow = true;
-       break;
-
-       /****************************************/
-       /* PRIMITIVE ARRAY ACCESS               */
-
-case ICMD_ARRAYLENGTH:
-       if (!TYPEINFO_MAYBE_ARRAY(OP1->typeinfo)
-                       && OP1->typeinfo.typeclass.cls != pseudo_class_Arraystub)
-               VERIFY_ERROR("illegal instruction: ARRAYLENGTH on non-array");
-       break;
-
-case ICMD_BALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BOOLEAN)
-                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BYTE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_CALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_CHAR))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_DALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_DOUBLE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_FALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_FLOAT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_IALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_INT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_SALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_SHORT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_LALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_LONG))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_BASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BOOLEAN)
-                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BYTE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_CASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_CHAR))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_DASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_DOUBLE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_FASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_FLOAT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_IASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_INT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_SASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_SHORT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_LASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_LONG))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_AASTORE:
-       /* we just check the basic input types and that the           */
-       /* destination is an array of references. Assignability to    */
-       /* the actual array must be checked at runtime, each time the */
-       /* instruction is performed. (See builtin_canstore.)          */
-       if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(OP1->typeinfo))
-               VERIFY_ERROR("illegal instruction: AASTORE to non-reference array");
-       break;
-
-case ICMD_IASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_INT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_LASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_LONG))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_BASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_BOOLEAN)
-                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_BYTE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_CASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_CHAR))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_SASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_SHORT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-       /****************************************/
-       /* ADDRESS CONSTANTS                    */
-
-case ICMD_ACONST: /* {ALL} */
-       if (IPTR->flags.bits & INS_FLAG_CLASS) {
-               /* a java.lang.Class reference */
-               TYPEINFO_INIT_JAVA_LANG_CLASS(DST->typeinfo,IPTR->sx.val.c);
-       }
-       else {
-               if (IPTR->sx.val.anyptr == NULL)
-                       TYPEINFO_INIT_NULLTYPE(DST->typeinfo);
-               else {
-                       /* string constant (or constant for builtin function) */
-                       typeinfo_init_classinfo(&(DST->typeinfo),class_java_lang_String);
-               }
-       }
-       break;
-
-       /****************************************/
-       /* CHECKCAST AND INSTANCEOF             */
-
-case ICMD_CHECKCAST: /* {ALL} */
-#if !defined(TYPECHECK_TYPEINFERER)
-       /* returnAddress is not allowed */
-       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
-               VERIFY_ERROR("Illegal instruction: CHECKCAST on non-reference");
-#endif
-
-    /* XXX only if narrower */
-       if (!typeinfo_init_class(&(DST->typeinfo),IPTR->sx.s23.s3.c))
-               EXCEPTION;
-       break;
-
-case ICMD_INSTANCEOF:
-       /* returnAddress is not allowed */
-       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
-               VERIFY_ERROR("Illegal instruction: INSTANCEOF on non-reference");
-
-       /* XXX should propagate type information to the following if-branches */
-       break;
-
-       /****************************************/
-       /* BRANCH INSTRUCTIONS                  */
-
-case ICMD_GOTO:            /* {ALL} */
-case ICMD_IFNULL:          /* {ALL} */
-case ICMD_IFNONNULL:       /* {ALL} */
-case ICMD_IFEQ:            /* {ALL} */
-case ICMD_IFNE:            /* {ALL} */
-case ICMD_IFLT:            /* {ALL} */
-case ICMD_IFGE:            /* {ALL} */
-case ICMD_IFGT:            /* {ALL} */
-case ICMD_IFLE:            /* {ALL} */
-case ICMD_IF_ICMPEQ:       /* {ALL} */
-case ICMD_IF_ICMPNE:       /* {ALL} */
-case ICMD_IF_ICMPLT:       /* {ALL} */
-case ICMD_IF_ICMPGE:       /* {ALL} */
-case ICMD_IF_ICMPGT:       /* {ALL} */
-case ICMD_IF_ICMPLE:       /* {ALL} */
-case ICMD_IF_ACMPEQ:       /* {ALL} */
-case ICMD_IF_ACMPNE:       /* {ALL} */
-
-case ICMD_IF_LEQ:          /* {ALL} */
-case ICMD_IF_LNE:          /* {ALL} */
-case ICMD_IF_LLT:          /* {ALL} */
-case ICMD_IF_LGE:          /* {ALL} */
-case ICMD_IF_LGT:          /* {ALL} */
-case ICMD_IF_LLE:          /* {ALL} */
-
-case ICMD_IF_LCMPEQ:       /* {ALL} */
-case ICMD_IF_LCMPNE:       /* {ALL} */
-case ICMD_IF_LCMPLT:       /* {ALL} */
-case ICMD_IF_LCMPGE:       /* {ALL} */
-case ICMD_IF_LCMPGT:       /* {ALL} */
-case ICMD_IF_LCMPLE:       /* {ALL} */
-       /* {RESULTNOW} */
-       TYPECHECK_COUNT(stat_ins_branch);
-
-       /* propagate stack and variables to the target block */
-       REACH(IPTR->dst);
-       break;
-
-       /****************************************/
-       /* SWITCHES                             */
-
-case ICMD_TABLESWITCH:     /* {ALL} */
-       /* {RESULTNOW} */
-       TYPECHECK_COUNT(stat_ins_switch);
-
-       table = IPTR->dst.table;
-       i = IPTR->sx.s23.s3.tablehigh
-       - IPTR->sx.s23.s2.tablelow + 1 + 1; /* plus default */
-
-       while (--i >= 0) {
-               REACH(*table);
-               table++;
-       }
-
-       LOG("switch done");
-       break;
-
-case ICMD_LOOKUPSWITCH:    /* {ALL} */
-       /* {RESULTNOW} */
-       TYPECHECK_COUNT(stat_ins_switch);
-
-       lookup = IPTR->dst.lookup;
-       i = IPTR->sx.s23.s2.lookupcount;
-       REACH(IPTR->sx.s23.s3.lookupdefault);
-
-       while (--i >= 0) {
-               REACH(lookup->target);
-               lookup++;
-       }
-
-       LOG("switch done");
-       break;
-
-
-       /****************************************/
-       /* ADDRESS RETURNS AND THROW            */
-
-case ICMD_ATHROW:
-       TYPECHECK_COUNT(stat_ins_athrow);
-       r = typeinfo_is_assignable_to_class(&OP1->typeinfo,
-                       CLASSREF_OR_CLASSINFO(class_java_lang_Throwable));
-       if (r == typecheck_FALSE)
-               VERIFY_ERROR("illegal instruction: ATHROW on non-Throwable");
-       if (r == typecheck_FAIL)
-               EXCEPTION;
-       if (r == typecheck_MAYBE) {
-               /* the check has to be postponed. we need a patcher */
-               TYPECHECK_COUNT(stat_ins_athrow_unresolved);
-               IPTR->sx.s23.s2.uc = create_unresolved_class(
-                               METHOD,
-                               /* XXX make this more efficient, use class_java_lang_Throwable
-                                * directly */
-                               class_get_classref(METHOD->clazz,utf_java_lang_Throwable),
-                               &OP1->typeinfo);
-               IPTR->flags.bits |= INS_FLAG_UNRESOLVED;
-       }
-       break;
-
-case ICMD_ARETURN:
-       TYPECHECK_COUNT(stat_ins_areturn);
-       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
-               VERIFY_ERROR("illegal instruction: ARETURN on non-reference");
-
-       if (STATE->returntype.type != TYPE_ADR
-                       || (r = typeinfo_is_assignable(&OP1->typeinfo,&(STATE->returntype.typeinfo)))
-                       == typecheck_FALSE)
-               VERIFY_ERROR("Return type mismatch");
-       if (r == typecheck_FAIL)
-               EXCEPTION;
-       if (r == typecheck_MAYBE) {
-               /* the check has to be postponed, we need a patcher */
-               TYPECHECK_COUNT(stat_ins_areturn_unresolved);
-               IPTR->sx.s23.s2.uc = create_unresolved_class(
-                               METHOD,
-                               METHOD->parseddesc->returntype.classref,
-                               &OP1->typeinfo);
-               IPTR->flags.bits |= INS_FLAG_UNRESOLVED;
-       }
-       goto return_tail;
-
-       /****************************************/
-       /* PRIMITIVE RETURNS                    */
-
-case ICMD_IRETURN:
-       if (STATE->returntype.type != TYPE_INT)
-               VERIFY_ERROR("Return type mismatch");
-       goto return_tail;
-
-case ICMD_LRETURN:
-       if (STATE->returntype.type != TYPE_LNG)
-               VERIFY_ERROR("Return type mismatch");
-       goto return_tail;
-
-case ICMD_FRETURN:
-       if (STATE->returntype.type != TYPE_FLT)
-               VERIFY_ERROR("Return type mismatch");
-       goto return_tail;
-
-case ICMD_DRETURN:
-       if (STATE->returntype.type != TYPE_DBL)
-               VERIFY_ERROR("Return type mismatch");
-       goto return_tail;
-
-case ICMD_RETURN:
-       if (STATE->returntype.type != TYPE_VOID)
-               VERIFY_ERROR("Return type mismatch");
-
-return_tail:
-       TYPECHECK_COUNT(stat_ins_primitive_return);
-
-       if (STATE->initmethod && METHOD->clazz != class_java_lang_Object) {
-               /* Check if the 'this' instance has been initialized. */
-               LOG("Checking <init> marker");
-#if defined(TYPECHECK_VARIABLESBASED)
-               if (!typevector_checktype(jd->var,STATE->numlocals-1,TYPE_INT))
-#else
-               if (STATE->locals[STATE->numlocals-1].type != TYPE_INT)
-#endif
-                       VERIFY_ERROR("<init> method does not initialize 'this'");
-       }
-       break;
-
-       /****************************************/
-       /* SUBROUTINE INSTRUCTIONS              */
-
-case ICMD_JSR: /* {VARIABLESBASED,TYPEINFERER} */
-       TYPEINFO_INIT_RETURNADDRESS(DST->typeinfo, BPTR->next);
-       REACH(IPTR->sx.s23.s3.jsrtarget);
-       break;
-
-case ICMD_JSR: /* {STACKBASED} */
-       /* {RESULTNOW} */
-       tbptr = IPTR->sx.s23.s3.jsrtarget.block;
-
-       TYPEINFO_INIT_RETURNADDRESS(stack[0].typeinfo, tbptr);
-       REACH_BLOCK(tbptr);
-
-       stack = typecheck_stackbased_jsr(STATE, stack, stackfloor);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_RET: /* {VARIABLESBASED,TYPEINFERER} */
-#if !defined(TYPECHECK_TYPEINFERER)
-       /* check returnAddress variable */
-       if (!typevector_checkretaddr(jd->var,IPTR->s1.varindex))
-               VERIFY_ERROR("illegal instruction: RET using non-returnAddress variable");
-#endif
-       REACH(IPTR->dst);
-       break;
-
-case ICMD_RET: /* {STACKBASED} */
-       /* {RESULTNOW} */
-       CHECK_LOCAL_TYPE(IPTR->s1.varindex, TYPE_RET);
-       if (!TYPEINFO_IS_PRIMITIVE(STATE->locals[IPTR->s1.varindex].typeinfo))
-               VERIFY_ERROR("illegal instruction: RET using non-returnAddress variable");
-
-       if (!typecheck_stackbased_ret(STATE, stack, stackfloor))
-               EXCEPTION;
-       break;
-
-       /****************************************/
-       /* INVOKATIONS                          */
-
-case ICMD_INVOKEVIRTUAL:   /* {VARIABLESBASED,TYPEINFERER} */
-case ICMD_INVOKESPECIAL:   /* {VARIABLESBASED,TYPEINFERER} */
-case ICMD_INVOKESTATIC:    /* {VARIABLESBASED,TYPEINFERER} */
-case ICMD_INVOKEINTERFACE: /* {VARIABLESBASED,TYPEINFERER} */
-       TYPECHECK_COUNT(stat_ins_invoke);
-       if (!handle_invocation(state))
-               EXCEPTION;
-       TYPECHECK_COUNTIF(INSTRUCTION_IS_UNRESOLVED(IPTR), stat_ins_invoke_unresolved);
-       break;
-
-case ICMD_INVOKEVIRTUAL:   /* {STACKBASED} */
-case ICMD_INVOKESPECIAL:   /* {STACKBASED} */
-case ICMD_INVOKESTATIC:    /* {STACKBASED} */
-case ICMD_INVOKEINTERFACE: /* {STACKBASED} */
-       TYPECHECK_COUNT(stat_ins_invoke);
-
-       INSTRUCTION_GET_METHODDESC(IPTR, md);
-       CHECK_STACK_DEPTH(md->paramslots);
-
-       if (!typecheck_stackbased_verify_invocation(STATE, stack, stackfloor))
-               EXCEPTION;
-
-       stack -= md->paramslots;
-
-       if (md->returntype.type != TYPE_VOID) {
-               if (IS_2_WORD_TYPE(md->returntype.type)) {
-                       CHECK_STACK_SPACE(2);
-                       stack += 2;
-                       stack[0].type = TYPE_VOID;
-                       stack[-1].type = md->returntype.type;
-               }
-               else {
-                       CHECK_STACK_SPACE(1);
-                       stack += 1;
-                       stack[0].type = md->returntype.type;
-               }
-       }
-       TYPECHECK_COUNTIF(INSTRUCTION_IS_UNRESOLVED(IPTR), stat_ins_invoke_unresolved);
-       break;
-
-       /****************************************/
-       /* MULTIANEWARRAY                       */
-
-case ICMD_MULTIANEWARRAY: /* {VARIABLESBASED,TYPEINFERER} */
-       if (!handle_multianewarray(STATE))
-               EXCEPTION;
-       break;
-
-case ICMD_MULTIANEWARRAY: /* {STACKBASED} */
-       if (!typecheck_stackbased_multianewarray(STATE, stack, stackfloor))
-               EXCEPTION;
-       stack -= (IPTR->s1.argcount - 1);
-       stack[0].type = TYPE_ADR;
-       break;
-
-       /****************************************/
-       /* BUILTINS                             */
-
-case ICMD_BUILTIN: /* {VARIABLESBASED,TYPEINFERER} */
-       TYPECHECK_COUNT(stat_ins_builtin);
-       if (!handle_builtin(state))
-               EXCEPTION;
-       break;
-
-case ICMD_BUILTIN: /* {STACKBASED} */
-       TYPECHECK_COUNT(stat_ins_builtin);
-       if (!typecheck_stackbased_verify_builtin(STATE, stack, stackfloor))
-               EXCEPTION;
-
-       /* pop operands and push return value */
-       {
-               u1 rtype = IPTR->sx.s23.s3.bte->md->returntype.type;
-               stack -=  IPTR->sx.s23.s3.bte->md->paramslots;
-               if (rtype != TYPE_VOID) {
-                       if (IS_2_WORD_TYPE(rtype))
-                               stack += 2;
-                       else
-                               stack += 1;
-               }
-       }
-       break;
-
-/* the following code is only used by the stackbased verifier */
-
-case ICMD_POP: /* {STACKBASED} */
-       /* we pop 1 */
-       CHECK_CAT1(stack[0]);
-       break;
-
-case ICMD_POP2: /* {STACKBASED} */
-       /* we pop either 11 or 2 */
-       if (IS_CAT1(stack[0]))
-               CHECK_CAT1(stack[-1]);
-       break;
-
-case ICMD_SWAP: /* {STACKBASED} */
-       CHECK_CAT1(stack[0]);
-       CHECK_CAT1(stack[-1]);
-
-       COPY_SLOT(stack[ 0], temp     );
-       COPY_SLOT(stack[-1], stack[ 0]);
-       COPY_SLOT(temp     , stack[-1]);
-       break;
-
-case ICMD_DUP: /* {STACKBASED} */
-       /* we dup 1 */
-       CHECK_CAT1(stack[0]);
-
-       COPY_SLOT(stack[ 0], stack[ 1]);
-       break;
-
-case ICMD_DUP_X1: /* {STACKBASED} */
-       /* we dup 1 */
-       CHECK_CAT1(stack[0]);
-       /* we skip 1 */
-       CHECK_CAT1(stack[-1]);
-
-       COPY_SLOT(stack[ 0], stack[ 1]);
-       COPY_SLOT(stack[-1], stack[ 0]);
-       COPY_SLOT(stack[ 1], stack[-1]);
-       break;
-
-case ICMD_DUP_X2: /* {STACKBASED} */
-       /* we dup 1 */
-       CHECK_CAT1(stack[0]);
-       /* we skip either 11 or 2 */
-       if (IS_CAT1(stack[-1]))
-               CHECK_CAT1(stack[-2]);
-
-       COPY_SLOT(stack[ 0], stack[ 1]);
-       COPY_SLOT(stack[-1], stack[ 0]);
-       COPY_SLOT(stack[-2], stack[-1]);
-       COPY_SLOT(stack[ 1], stack[-2]);
-       break;
-
-case ICMD_DUP2: /* {STACKBASED} */
-       /* we dup either 11 or 2 */
-       if (IS_CAT1(stack[0]))
-               CHECK_CAT1(stack[-1]);
-
-       COPY_SLOT(stack[ 0], stack[ 2]);
-       COPY_SLOT(stack[-1], stack[ 1]);
-       break;
-
-case ICMD_DUP2_X1: /* {STACKBASED} */
-       /* we dup either 11 or 2 */
-       if (IS_CAT1(stack[0]))
-               CHECK_CAT1(stack[-1]);
-       /* we skip 1 */
-       CHECK_CAT1(stack[-2]);
-
-       COPY_SLOT(stack[ 0], stack[ 2]);
-       COPY_SLOT(stack[-1], stack[ 1]);
-       COPY_SLOT(stack[-2], stack[ 0]);
-       COPY_SLOT(stack[ 2], stack[-1]);
-       COPY_SLOT(stack[ 1], stack[-2]);
-       break;
-
-case ICMD_DUP2_X2: /* {STACKBASED} */
-       /* we dup either 11 or 2 */
-       if (IS_CAT1(stack[0]))
-               CHECK_CAT1(stack[-1]);
-       /* we skip either 11 or 2 */
-       if (IS_CAT1(stack[-2]))
-               CHECK_CAT1(stack[-3]);
-
-       COPY_SLOT(stack[ 0], stack[ 2]);
-       COPY_SLOT(stack[-1], stack[ 1]);
-       COPY_SLOT(stack[-2], stack[ 0]);
-       COPY_SLOT(stack[-3], stack[-1]);
-       COPY_SLOT(stack[ 2], stack[-2]);
-       COPY_SLOT(stack[ 1], stack[-3]);
-       break;
-
-
-/* this marker is needed by generate.pl: */
-/* {END_OF_CODE} */
-
-/*
- * 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/jit/verify/icmds.cpp b/src/vm/jit/verify/icmds.cpp
new file mode 100644 (file)
index 0000000..0d3457e
--- /dev/null
@@ -0,0 +1,779 @@
+/* src/vm/jit/verify/icmds.c - ICMD-specific type checking code
+
+   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.
+
+*/
+
+#if 0 /* (needed for code examples in the following comment) */
+/******************************************************************************/
+/* This file contains ICMD-specific code for type checking and type
+ * inference. It is an input file for the verifier generator
+ * (src/vm/jit/verify/generate.pl). The verifier generator creates
+ * code for three compiler passes:
+ *     - stack-based type-infering verification
+ *     - vasiables-based type-infering verification
+ *     - type inference pass (no verification - used for optimizing compiler)
+ *
+ * The rest of this file must consist of "case" clauses starting in
+ * the first column. Each clause can be marked with tags like this:
+ *
+ */          case ICMD_CONSTANT: /* {TAG, TAG, ...} */
+/*
+ * This must be on one line. The following tags are defined:
+ *     STACKBASED..........use this clause for the stack-based verifier
+ *     VARIABLESBASED......use this clause for the variables-based verifier
+ *     TYPEINFERER.........use this clause for the type inference pass
+ *     ALL.................use for all passes
+ *
+ * If no tag is specified, {STACKBASED,VARIABLESBASED} is assumed.
+ *
+ * There are also tags that can be used inside a clause like this:
+ *
+ */          /* {TAG} */
+/*
+ * The following tags are defined within clauses:
+ *     RESULTNOW...........generate code for modelling the stack action
+ *                         _before_ the user-defined code in the clause
+ *                         (Default is to model the stack action afterwards.)
+ *
+ * The following macros are pre-defined:
+ *
+ *     TYPECHECK_STACKBASED.......iff compiling the stack-based verifier
+ *     TYPECHECK_VARIABLESBASED...iff compiling the variables-based verifier
+ *     TYPECHECK_TYPEINFERER......iff compiling the type inference pass
+ *
+/******************************************************************************/
+#endif /* (end #if 0) */
+
+
+/* this marker is needed by generate.pl: */
+/* {START_OF_CODE} */
+
+       /****************************************/
+       /* MOVE/COPY                            */
+
+       /* We just need to copy the typeinfo */
+       /* for slots containing addresses.   */
+
+       /* (These are only used by the variables based verifier.) */
+
+case ICMD_MOVE: /* {VARIABLESBASED,TYPEINFERER} */
+case ICMD_COPY: /* {VARIABLESBASED,TYPEINFERER} */
+       TYPECHECK_COUNT(stat_ins_stack);
+       COPYTYPE(IPTR->s1, IPTR->dst);
+       DST->type = OP1->type;
+       break;
+
+       /****************************************/
+       /* LOADING ADDRESS FROM VARIABLE        */
+
+case ICMD_ALOAD: /* {ALL} */
+       TYPECHECK_COUNT(stat_ins_aload);
+
+#if !defined(TYPECHECK_TYPEINFERER)
+       /* loading a returnAddress is not allowed */
+       if (!TYPEDESC_IS_REFERENCE(*OP1)) {
+               VERIFY_ERROR("illegal instruction: ALOAD loading non-reference");
+       }
+#endif
+       TYPEINFO_COPY(OP1->typeinfo,DST->typeinfo);
+       break;
+
+       /****************************************/
+       /* STORING ADDRESS TO VARIABLE          */
+
+case ICMD_ASTORE: /* {ALL} */
+       TYPEINFO_COPY(OP1->typeinfo, DST->typeinfo);
+       break;
+
+       /****************************************/
+       /* LOADING ADDRESS FROM ARRAY           */
+
+case ICMD_AALOAD: /* {ALL} */
+#if !defined(TYPECHECK_TYPEINFERER)
+       if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(OP1->typeinfo))
+               VERIFY_ERROR("illegal instruction: AALOAD on non-reference array");
+#endif
+
+       if (!typeinfo_init_component(&OP1->typeinfo,&DST->typeinfo))
+               EXCEPTION;
+       break;
+
+       /****************************************/
+       /* FIELD ACCESS                         */
+
+case ICMD_PUTFIELD: /* {STACKBASED} */
+       CHECK_STACK_DEPTH(2);
+       if (!IS_CAT1(stack[0])) {
+               CHECK_STACK_DEPTH(3);
+               stack -= 1;
+       }
+       CHECK_STACK_TYPE(stack[-1], TYPE_ADR);
+       stack = typecheck_stackbased_verify_fieldaccess(STATE, stack-1, stack, stack-2);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_PUTSTATIC: /* {STACKBASED} */
+       CHECK_STACK_DEPTH(1);
+       if (!IS_CAT1(stack[0])) {
+               /* (stack depth >= 2 is guaranteed) */
+               stack -= 1;
+       }
+       stack = typecheck_stackbased_verify_fieldaccess(STATE, NULL, stack, stack-1);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_GETFIELD: /* {STACKBASED} */
+       CHECK_STACK_TYPE(stack[0], TYPE_ADR);
+       stack = typecheck_stackbased_verify_fieldaccess(STATE, stack, NULL, stack-1);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_GETSTATIC:      /* {STACKBASED} */
+       stack = typecheck_stackbased_verify_fieldaccess(STATE, NULL, NULL, stack);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_PUTFIELD:       /* {VARIABLESBASED} */
+       if (!handle_fieldaccess(state, VAROP(iptr->s1), VAROP(iptr->sx.s23.s2)))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_PUTSTATIC:      /* {VARIABLESBASED} */
+       if (!handle_fieldaccess(state, NULL, VAROP(iptr->s1)))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_PUTFIELDCONST:  /* {VARIABLESBASED} */
+       /* XXX this mess will go away with const operands */
+       INSTRUCTION_GET_FIELDREF(state->iptr, fieldref);
+       constvalue.type = fieldref->parseddesc.fd->type;
+       if (IS_ADR_TYPE(constvalue.type)) {
+               if (state->iptr->sx.val.anyptr) {
+                       classinfo *cc = (state->iptr->flags.bits & INS_FLAG_CLASS)
+                               ? class_java_lang_Class : class_java_lang_String;
+                       assert(cc);
+                       assert(cc->state & CLASS_LINKED);
+                       typeinfo_init_classinfo(&(constvalue.typeinfo), cc);
+               }
+               else {
+                       TYPEINFO_INIT_NULLTYPE(constvalue.typeinfo);
+               }
+       }
+       if (!handle_fieldaccess(state, VAROP(iptr->s1), &constvalue))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_PUTSTATICCONST: /* {VARIABLESBASED} */
+       /* XXX this mess will go away with const operands */
+       INSTRUCTION_GET_FIELDREF(state->iptr, fieldref);
+       constvalue.type = fieldref->parseddesc.fd->type;
+       if (IS_ADR_TYPE(constvalue.type)) {
+               if (state->iptr->sx.val.anyptr) {
+                       classinfo *cc = (state->iptr->flags.bits & INS_FLAG_CLASS)
+                               ? class_java_lang_Class : class_java_lang_String;
+                       assert(cc);
+                       assert(cc->state & CLASS_LINKED);
+                       typeinfo_init_classinfo(&(constvalue.typeinfo), cc);
+               }
+               else {
+                       TYPEINFO_INIT_NULLTYPE(constvalue.typeinfo);
+               }
+       }
+       if (!handle_fieldaccess(state, NULL, &constvalue))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_GETFIELD:       /* {VARIABLESBASED,TYPEINFERER} */
+       if (!handle_fieldaccess(state, VAROP(iptr->s1), NULL))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_GETSTATIC:      /* {VARIABLESBASED,TYPEINFERER} */
+       if (!handle_fieldaccess(state, NULL, NULL))
+               return false;
+       maythrow = true;
+       break;
+
+       /****************************************/
+       /* PRIMITIVE ARRAY ACCESS               */
+
+case ICMD_ARRAYLENGTH:
+       if (!TYPEINFO_MAYBE_ARRAY(OP1->typeinfo)
+                       && OP1->typeinfo.typeclass.cls != pseudo_class_Arraystub)
+               VERIFY_ERROR("illegal instruction: ARRAYLENGTH on non-array");
+       break;
+
+case ICMD_BALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BOOLEAN)
+                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BYTE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_CALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_CHAR))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_DALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_DOUBLE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_FALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_FLOAT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_IALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_INT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_SALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_SHORT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_LALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_LONG))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_BASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BOOLEAN)
+                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BYTE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_CASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_CHAR))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_DASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_DOUBLE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_FASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_FLOAT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_IASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_INT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_SASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_SHORT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_LASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_LONG))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_AASTORE:
+       /* we just check the basic input types and that the           */
+       /* destination is an array of references. Assignability to    */
+       /* the actual array must be checked at runtime, each time the */
+       /* instruction is performed. (See builtin_canstore.)          */
+       if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(OP1->typeinfo))
+               VERIFY_ERROR("illegal instruction: AASTORE to non-reference array");
+       break;
+
+case ICMD_IASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_INT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_LASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_LONG))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_BASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_BOOLEAN)
+                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_BYTE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_CASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_CHAR))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_SASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_SHORT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+       /****************************************/
+       /* ADDRESS CONSTANTS                    */
+
+case ICMD_ACONST: /* {ALL} */
+       if (IPTR->flags.bits & INS_FLAG_CLASS) {
+               /* a java.lang.Class reference */
+               TYPEINFO_INIT_JAVA_LANG_CLASS(DST->typeinfo,IPTR->sx.val.c);
+       }
+       else {
+               if (IPTR->sx.val.anyptr == NULL)
+                       TYPEINFO_INIT_NULLTYPE(DST->typeinfo);
+               else {
+                       /* string constant (or constant for builtin function) */
+                       typeinfo_init_classinfo(&(DST->typeinfo),class_java_lang_String);
+               }
+       }
+       break;
+
+       /****************************************/
+       /* CHECKCAST AND INSTANCEOF             */
+
+case ICMD_CHECKCAST: /* {ALL} */
+#if !defined(TYPECHECK_TYPEINFERER)
+       /* returnAddress is not allowed */
+       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
+               VERIFY_ERROR("Illegal instruction: CHECKCAST on non-reference");
+#endif
+
+    /* XXX only if narrower */
+       if (!typeinfo_init_class(&(DST->typeinfo),IPTR->sx.s23.s3.c))
+               EXCEPTION;
+       break;
+
+case ICMD_INSTANCEOF:
+       /* returnAddress is not allowed */
+       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
+               VERIFY_ERROR("Illegal instruction: INSTANCEOF on non-reference");
+
+       /* XXX should propagate type information to the following if-branches */
+       break;
+
+       /****************************************/
+       /* BRANCH INSTRUCTIONS                  */
+
+case ICMD_GOTO:            /* {ALL} */
+case ICMD_IFNULL:          /* {ALL} */
+case ICMD_IFNONNULL:       /* {ALL} */
+case ICMD_IFEQ:            /* {ALL} */
+case ICMD_IFNE:            /* {ALL} */
+case ICMD_IFLT:            /* {ALL} */
+case ICMD_IFGE:            /* {ALL} */
+case ICMD_IFGT:            /* {ALL} */
+case ICMD_IFLE:            /* {ALL} */
+case ICMD_IF_ICMPEQ:       /* {ALL} */
+case ICMD_IF_ICMPNE:       /* {ALL} */
+case ICMD_IF_ICMPLT:       /* {ALL} */
+case ICMD_IF_ICMPGE:       /* {ALL} */
+case ICMD_IF_ICMPGT:       /* {ALL} */
+case ICMD_IF_ICMPLE:       /* {ALL} */
+case ICMD_IF_ACMPEQ:       /* {ALL} */
+case ICMD_IF_ACMPNE:       /* {ALL} */
+
+case ICMD_IF_LEQ:          /* {ALL} */
+case ICMD_IF_LNE:          /* {ALL} */
+case ICMD_IF_LLT:          /* {ALL} */
+case ICMD_IF_LGE:          /* {ALL} */
+case ICMD_IF_LGT:          /* {ALL} */
+case ICMD_IF_LLE:          /* {ALL} */
+
+case ICMD_IF_LCMPEQ:       /* {ALL} */
+case ICMD_IF_LCMPNE:       /* {ALL} */
+case ICMD_IF_LCMPLT:       /* {ALL} */
+case ICMD_IF_LCMPGE:       /* {ALL} */
+case ICMD_IF_LCMPGT:       /* {ALL} */
+case ICMD_IF_LCMPLE:       /* {ALL} */
+       /* {RESULTNOW} */
+       TYPECHECK_COUNT(stat_ins_branch);
+
+       /* propagate stack and variables to the target block */
+       REACH(IPTR->dst);
+       break;
+
+       /****************************************/
+       /* SWITCHES                             */
+
+case ICMD_TABLESWITCH:     /* {ALL} */
+       /* {RESULTNOW} */
+       TYPECHECK_COUNT(stat_ins_switch);
+
+       table = IPTR->dst.table;
+       i = IPTR->sx.s23.s3.tablehigh
+       - IPTR->sx.s23.s2.tablelow + 1 + 1; /* plus default */
+
+       while (--i >= 0) {
+               REACH(*table);
+               table++;
+       }
+
+       LOG("switch done");
+       break;
+
+case ICMD_LOOKUPSWITCH:    /* {ALL} */
+       /* {RESULTNOW} */
+       TYPECHECK_COUNT(stat_ins_switch);
+
+       lookup = IPTR->dst.lookup;
+       i = IPTR->sx.s23.s2.lookupcount;
+       REACH(IPTR->sx.s23.s3.lookupdefault);
+
+       while (--i >= 0) {
+               REACH(lookup->target);
+               lookup++;
+       }
+
+       LOG("switch done");
+       break;
+
+
+       /****************************************/
+       /* ADDRESS RETURNS AND THROW            */
+
+case ICMD_ATHROW:
+       TYPECHECK_COUNT(stat_ins_athrow);
+       r = typeinfo_is_assignable_to_class(&OP1->typeinfo,
+                       CLASSREF_OR_CLASSINFO(class_java_lang_Throwable));
+       if (r == typecheck_FALSE)
+               VERIFY_ERROR("illegal instruction: ATHROW on non-Throwable");
+       if (r == typecheck_FAIL)
+               EXCEPTION;
+       if (r == typecheck_MAYBE) {
+               /* the check has to be postponed. we need a patcher */
+               TYPECHECK_COUNT(stat_ins_athrow_unresolved);
+               IPTR->sx.s23.s2.uc = create_unresolved_class(
+                               METHOD,
+                               /* XXX make this more efficient, use class_java_lang_Throwable
+                                * directly */
+                               class_get_classref(METHOD->clazz,utf_java_lang_Throwable),
+                               &OP1->typeinfo);
+               IPTR->flags.bits |= INS_FLAG_UNRESOLVED;
+       }
+       break;
+
+case ICMD_ARETURN:
+       TYPECHECK_COUNT(stat_ins_areturn);
+       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
+               VERIFY_ERROR("illegal instruction: ARETURN on non-reference");
+
+       if (STATE->returntype.type != TYPE_ADR
+                       || (r = typeinfo_is_assignable(&OP1->typeinfo,&(STATE->returntype.typeinfo)))
+                       == typecheck_FALSE)
+               VERIFY_ERROR("Return type mismatch");
+       if (r == typecheck_FAIL)
+               EXCEPTION;
+       if (r == typecheck_MAYBE) {
+               /* the check has to be postponed, we need a patcher */
+               TYPECHECK_COUNT(stat_ins_areturn_unresolved);
+               IPTR->sx.s23.s2.uc = create_unresolved_class(
+                               METHOD,
+                               METHOD->parseddesc->returntype.classref,
+                               &OP1->typeinfo);
+               IPTR->flags.bits |= INS_FLAG_UNRESOLVED;
+       }
+       goto return_tail;
+
+       /****************************************/
+       /* PRIMITIVE RETURNS                    */
+
+case ICMD_IRETURN:
+       if (STATE->returntype.type != TYPE_INT)
+               VERIFY_ERROR("Return type mismatch");
+       goto return_tail;
+
+case ICMD_LRETURN:
+       if (STATE->returntype.type != TYPE_LNG)
+               VERIFY_ERROR("Return type mismatch");
+       goto return_tail;
+
+case ICMD_FRETURN:
+       if (STATE->returntype.type != TYPE_FLT)
+               VERIFY_ERROR("Return type mismatch");
+       goto return_tail;
+
+case ICMD_DRETURN:
+       if (STATE->returntype.type != TYPE_DBL)
+               VERIFY_ERROR("Return type mismatch");
+       goto return_tail;
+
+case ICMD_RETURN:
+       if (STATE->returntype.type != TYPE_VOID)
+               VERIFY_ERROR("Return type mismatch");
+
+return_tail:
+       TYPECHECK_COUNT(stat_ins_primitive_return);
+
+       if (STATE->initmethod && METHOD->clazz != class_java_lang_Object) {
+               /* Check if the 'this' instance has been initialized. */
+               LOG("Checking <init> marker");
+#if defined(TYPECHECK_VARIABLESBASED)
+               if (!typevector_checktype(jd->var,STATE->numlocals-1,TYPE_INT))
+#else
+               if (STATE->locals[STATE->numlocals-1].type != TYPE_INT)
+#endif
+                       VERIFY_ERROR("<init> method does not initialize 'this'");
+       }
+       break;
+
+       /****************************************/
+       /* SUBROUTINE INSTRUCTIONS              */
+
+case ICMD_JSR: /* {VARIABLESBASED,TYPEINFERER} */
+       TYPEINFO_INIT_RETURNADDRESS(DST->typeinfo, BPTR->next);
+       REACH(IPTR->sx.s23.s3.jsrtarget);
+       break;
+
+case ICMD_JSR: /* {STACKBASED} */
+       /* {RESULTNOW} */
+       tbptr = IPTR->sx.s23.s3.jsrtarget.block;
+
+       TYPEINFO_INIT_RETURNADDRESS(stack[0].typeinfo, tbptr);
+       REACH_BLOCK(tbptr);
+
+       stack = typecheck_stackbased_jsr(STATE, stack, stackfloor);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_RET: /* {VARIABLESBASED,TYPEINFERER} */
+#if !defined(TYPECHECK_TYPEINFERER)
+       /* check returnAddress variable */
+       if (!typevector_checkretaddr(jd->var,IPTR->s1.varindex))
+               VERIFY_ERROR("illegal instruction: RET using non-returnAddress variable");
+#endif
+       REACH(IPTR->dst);
+       break;
+
+case ICMD_RET: /* {STACKBASED} */
+       /* {RESULTNOW} */
+       CHECK_LOCAL_TYPE(IPTR->s1.varindex, TYPE_RET);
+       if (!TYPEINFO_IS_PRIMITIVE(STATE->locals[IPTR->s1.varindex].typeinfo))
+               VERIFY_ERROR("illegal instruction: RET using non-returnAddress variable");
+
+       if (!typecheck_stackbased_ret(STATE, stack, stackfloor))
+               EXCEPTION;
+       break;
+
+       /****************************************/
+       /* INVOKATIONS                          */
+
+case ICMD_INVOKEVIRTUAL:   /* {VARIABLESBASED,TYPEINFERER} */
+case ICMD_INVOKESPECIAL:   /* {VARIABLESBASED,TYPEINFERER} */
+case ICMD_INVOKESTATIC:    /* {VARIABLESBASED,TYPEINFERER} */
+case ICMD_INVOKEINTERFACE: /* {VARIABLESBASED,TYPEINFERER} */
+       TYPECHECK_COUNT(stat_ins_invoke);
+       if (!handle_invocation(state))
+               EXCEPTION;
+       TYPECHECK_COUNTIF(INSTRUCTION_IS_UNRESOLVED(IPTR), stat_ins_invoke_unresolved);
+       break;
+
+case ICMD_INVOKEVIRTUAL:   /* {STACKBASED} */
+case ICMD_INVOKESPECIAL:   /* {STACKBASED} */
+case ICMD_INVOKESTATIC:    /* {STACKBASED} */
+case ICMD_INVOKEINTERFACE: /* {STACKBASED} */
+       TYPECHECK_COUNT(stat_ins_invoke);
+
+       INSTRUCTION_GET_METHODDESC(IPTR, md);
+       CHECK_STACK_DEPTH(md->paramslots);
+
+       if (!typecheck_stackbased_verify_invocation(STATE, stack, stackfloor))
+               EXCEPTION;
+
+       stack -= md->paramslots;
+
+       if (md->returntype.type != TYPE_VOID) {
+               if (IS_2_WORD_TYPE(md->returntype.type)) {
+                       CHECK_STACK_SPACE(2);
+                       stack += 2;
+                       stack[0].type = TYPE_VOID;
+                       stack[-1].type = md->returntype.type;
+               }
+               else {
+                       CHECK_STACK_SPACE(1);
+                       stack += 1;
+                       stack[0].type = md->returntype.type;
+               }
+       }
+       TYPECHECK_COUNTIF(INSTRUCTION_IS_UNRESOLVED(IPTR), stat_ins_invoke_unresolved);
+       break;
+
+       /****************************************/
+       /* MULTIANEWARRAY                       */
+
+case ICMD_MULTIANEWARRAY: /* {VARIABLESBASED,TYPEINFERER} */
+       if (!handle_multianewarray(STATE))
+               EXCEPTION;
+       break;
+
+case ICMD_MULTIANEWARRAY: /* {STACKBASED} */
+       if (!typecheck_stackbased_multianewarray(STATE, stack, stackfloor))
+               EXCEPTION;
+       stack -= (IPTR->s1.argcount - 1);
+       stack[0].type = TYPE_ADR;
+       break;
+
+       /****************************************/
+       /* BUILTINS                             */
+
+case ICMD_BUILTIN: /* {VARIABLESBASED,TYPEINFERER} */
+       TYPECHECK_COUNT(stat_ins_builtin);
+       if (!handle_builtin(state))
+               EXCEPTION;
+       break;
+
+case ICMD_BUILTIN: /* {STACKBASED} */
+       TYPECHECK_COUNT(stat_ins_builtin);
+       if (!typecheck_stackbased_verify_builtin(STATE, stack, stackfloor))
+               EXCEPTION;
+
+       /* pop operands and push return value */
+       {
+               u1 rtype = IPTR->sx.s23.s3.bte->md->returntype.type;
+               stack -=  IPTR->sx.s23.s3.bte->md->paramslots;
+               if (rtype != TYPE_VOID) {
+                       if (IS_2_WORD_TYPE(rtype))
+                               stack += 2;
+                       else
+                               stack += 1;
+               }
+       }
+       break;
+
+/* the following code is only used by the stackbased verifier */
+
+case ICMD_POP: /* {STACKBASED} */
+       /* we pop 1 */
+       CHECK_CAT1(stack[0]);
+       break;
+
+case ICMD_POP2: /* {STACKBASED} */
+       /* we pop either 11 or 2 */
+       if (IS_CAT1(stack[0]))
+               CHECK_CAT1(stack[-1]);
+       break;
+
+case ICMD_SWAP: /* {STACKBASED} */
+       CHECK_CAT1(stack[0]);
+       CHECK_CAT1(stack[-1]);
+
+       COPY_SLOT(stack[ 0], temp     );
+       COPY_SLOT(stack[-1], stack[ 0]);
+       COPY_SLOT(temp     , stack[-1]);
+       break;
+
+case ICMD_DUP: /* {STACKBASED} */
+       /* we dup 1 */
+       CHECK_CAT1(stack[0]);
+
+       COPY_SLOT(stack[ 0], stack[ 1]);
+       break;
+
+case ICMD_DUP_X1: /* {STACKBASED} */
+       /* we dup 1 */
+       CHECK_CAT1(stack[0]);
+       /* we skip 1 */
+       CHECK_CAT1(stack[-1]);
+
+       COPY_SLOT(stack[ 0], stack[ 1]);
+       COPY_SLOT(stack[-1], stack[ 0]);
+       COPY_SLOT(stack[ 1], stack[-1]);
+       break;
+
+case ICMD_DUP_X2: /* {STACKBASED} */
+       /* we dup 1 */
+       CHECK_CAT1(stack[0]);
+       /* we skip either 11 or 2 */
+       if (IS_CAT1(stack[-1]))
+               CHECK_CAT1(stack[-2]);
+
+       COPY_SLOT(stack[ 0], stack[ 1]);
+       COPY_SLOT(stack[-1], stack[ 0]);
+       COPY_SLOT(stack[-2], stack[-1]);
+       COPY_SLOT(stack[ 1], stack[-2]);
+       break;
+
+case ICMD_DUP2: /* {STACKBASED} */
+       /* we dup either 11 or 2 */
+       if (IS_CAT1(stack[0]))
+               CHECK_CAT1(stack[-1]);
+
+       COPY_SLOT(stack[ 0], stack[ 2]);
+       COPY_SLOT(stack[-1], stack[ 1]);
+       break;
+
+case ICMD_DUP2_X1: /* {STACKBASED} */
+       /* we dup either 11 or 2 */
+       if (IS_CAT1(stack[0]))
+               CHECK_CAT1(stack[-1]);
+       /* we skip 1 */
+       CHECK_CAT1(stack[-2]);
+
+       COPY_SLOT(stack[ 0], stack[ 2]);
+       COPY_SLOT(stack[-1], stack[ 1]);
+       COPY_SLOT(stack[-2], stack[ 0]);
+       COPY_SLOT(stack[ 2], stack[-1]);
+       COPY_SLOT(stack[ 1], stack[-2]);
+       break;
+
+case ICMD_DUP2_X2: /* {STACKBASED} */
+       /* we dup either 11 or 2 */
+       if (IS_CAT1(stack[0]))
+               CHECK_CAT1(stack[-1]);
+       /* we skip either 11 or 2 */
+       if (IS_CAT1(stack[-2]))
+               CHECK_CAT1(stack[-3]);
+
+       COPY_SLOT(stack[ 0], stack[ 2]);
+       COPY_SLOT(stack[-1], stack[ 1]);
+       COPY_SLOT(stack[-2], stack[ 0]);
+       COPY_SLOT(stack[-3], stack[-1]);
+       COPY_SLOT(stack[ 2], stack[-2]);
+       COPY_SLOT(stack[ 1], stack[-3]);
+       break;
+
+
+/* this marker is needed by generate.pl: */
+/* {END_OF_CODE} */
+
+/*
+ * 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/jit/verify/typecheck-common.c b/src/vm/jit/verify/typecheck-common.c
deleted file mode 100644 (file)
index 7b2cdd1..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-/* src/vm/jit/verify/typecheck-common.c - shared verifier code
-
-   Copyright (C) 1996-2005, 2006, 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 "vm/types.h"
-#include "vm/global.h"
-
-#include <assert.h>
-
-#include "vm/exceptions.hpp"
-#include "vm/globals.hpp"
-
-#include "vm/jit/show.hpp"
-
-#include "typecheck-common.h"
-
-
-/****************************************************************************/
-/* DEBUG HELPERS                                                            */
-/****************************************************************************/
-
-#ifdef TYPECHECK_VERBOSE_OPT
-bool opt_typecheckverbose = false;
-#endif
-
-#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
-
-void typecheck_print_var(FILE *file, jitdata *jd, s4 index)
-{
-       varinfo *var;
-
-       assert(index >= 0 && index < jd->varcount);
-       var = VAR(index);
-       typeinfo_print_type(file, var->type, &(var->typeinfo));
-}
-
-void typecheck_print_vararray(FILE *file, jitdata *jd, s4 *vars, int len)
-{
-       s4 i;
-
-       for (i=0; i<len; ++i) {
-               if (i)
-                       fputc(' ', file);
-               typecheck_print_var(file, jd, *vars++);
-       }
-}
-
-#endif /* defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT) */
-
-
-/****************************************************************************/
-/* STATISTICS                                                               */
-/****************************************************************************/
-
-#if defined(TYPECHECK_STATISTICS)
-int stat_typechecked = 0;
-int stat_methods_with_handlers = 0;
-int stat_methods_maythrow = 0;
-int stat_iterations[STAT_ITERATIONS+1] = { 0 };
-int stat_reached = 0;
-int stat_copied = 0;
-int stat_merged = 0;
-int stat_merging_changed = 0;
-int stat_blocks[STAT_BLOCKS+1] = { 0 };
-int stat_locals[STAT_LOCALS+1] = { 0 };
-int stat_ins = 0;
-int stat_ins_maythrow = 0;
-int stat_ins_stack = 0;
-int stat_ins_field = 0;
-int stat_ins_field_unresolved = 0;
-int stat_ins_field_uninitialized = 0;
-int stat_ins_invoke = 0;
-int stat_ins_invoke_unresolved = 0;
-int stat_ins_primload = 0;
-int stat_ins_aload = 0;
-int stat_ins_builtin = 0;
-int stat_ins_builtin_gen = 0;
-int stat_ins_branch = 0;
-int stat_ins_switch = 0;
-int stat_ins_primitive_return = 0;
-int stat_ins_areturn = 0;
-int stat_ins_areturn_unresolved = 0;
-int stat_ins_athrow = 0;
-int stat_ins_athrow_unresolved = 0;
-int stat_ins_unchecked = 0;
-int stat_handlers_reached = 0;
-int stat_savedstack = 0;
-
-static void print_freq(FILE *file,int *array,int limit)
-{
-       int i;
-       for (i=0; i<limit; ++i)
-               fprintf(file,"      %3d: %8d\n",i,array[i]);
-       fprintf(file,"    >=%3d: %8d\n",limit,array[limit]);
-}
-
-void typecheck_print_statistics(FILE *file) {
-       fprintf(file,"typechecked methods: %8d\n",stat_typechecked);
-       fprintf(file,"    with handler(s): %8d\n",stat_methods_with_handlers);
-       fprintf(file,"    with throw(s)  : %8d\n",stat_methods_maythrow);
-       fprintf(file,"reached blocks     : %8d\n",stat_reached);
-       fprintf(file,"copied states      : %8d\n",stat_copied);
-       fprintf(file,"merged states      : %8d\n",stat_merged);
-       fprintf(file,"merging changed    : %8d\n",stat_merging_changed);
-       fprintf(file,"handlers reached   : %8d\n",stat_handlers_reached);
-       fprintf(file,"saved stack (times): %8d\n",stat_savedstack);
-       fprintf(file,"instructions       : %8d\n",stat_ins);
-       fprintf(file,"    stack          : %8d\n",stat_ins_stack);
-       fprintf(file,"    field access   : %8d\n",stat_ins_field);
-       fprintf(file,"      (unresolved) : %8d\n",stat_ins_field_unresolved);
-       fprintf(file,"      (uninit.)    : %8d\n",stat_ins_field_uninitialized);
-       fprintf(file,"    invocations    : %8d\n",stat_ins_invoke);
-       fprintf(file,"      (unresolved) : %8d\n",stat_ins_invoke_unresolved);
-       fprintf(file,"    load primitive : (currently not counted) %8d\n",stat_ins_primload);
-       fprintf(file,"    load address   : %8d\n",stat_ins_aload);
-       fprintf(file,"    builtins       : %8d\n",stat_ins_builtin);
-       fprintf(file,"        generic    : %8d\n",stat_ins_builtin_gen);
-       fprintf(file,"    branches       : %8d\n",stat_ins_branch);
-       fprintf(file,"    switches       : %8d\n",stat_ins_switch);
-       fprintf(file,"    prim. return   : %8d\n",stat_ins_primitive_return);
-       fprintf(file,"    areturn        : %8d\n",stat_ins_areturn);
-       fprintf(file,"      (unresolved) : %8d\n",stat_ins_areturn_unresolved);
-       fprintf(file,"    athrow         : %8d\n",stat_ins_athrow);
-       fprintf(file,"      (unresolved) : %8d\n",stat_ins_athrow_unresolved);
-       fprintf(file,"    unchecked      : %8d\n",stat_ins_unchecked);
-       fprintf(file,"    maythrow       : %8d\n",stat_ins_maythrow);
-       fprintf(file,"iterations used:\n");
-       print_freq(file,stat_iterations,STAT_ITERATIONS);
-       fprintf(file,"basic blocks per method / 10:\n");
-       print_freq(file,stat_blocks,STAT_BLOCKS);
-       fprintf(file,"locals:\n");
-       print_freq(file,stat_locals,STAT_LOCALS);
-}
-#endif /* defined(TYPECHECK_STATISTICS) */
-
-
-/* typecheck_init_flags ********************************************************
-   Initialize the basic block flags for the following CFG traversal.
-  
-   IN:
-       state............the current state of the verifier
-       minflags.........minimum flags value of blocks that should be
-                        considered
-
-*******************************************************************************/
-
-void typecheck_init_flags(verifier_state *state, s4 minflags)
-{
-       basicblock *block;
-
-    /* set all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
-       
-    for (block = state->basicblocks; block; block = block->next) {
-               
-#ifdef TYPECHECK_DEBUG
-               /* check for invalid flags */
-        if (block->flags != BBFINISHED && block->flags != BBDELETED && block->flags != BBUNDEF)
-        {
-            LOGSTR1("block flags: %d\n",block->flags); LOGFLUSH;
-                       TYPECHECK_ASSERT(false);
-        }
-#endif
-
-        if (block->flags >= minflags) {
-            block->flags = BBTYPECHECK_UNDEF;
-        }
-    }
-
-    /* the first block is always reached */
-       
-    if (state->basicblockcount && state->basicblocks[0].flags == BBTYPECHECK_UNDEF)
-        state->basicblocks[0].flags = BBTYPECHECK_REACHED;
-}
-
-
-/* typecheck_reset_flags *******************************************************
-   Reset the flags of basic blocks we have not reached.
-  
-   IN:
-       state............the current state of the verifier
-
-*******************************************************************************/
-
-void typecheck_reset_flags(verifier_state *state)
-{
-       basicblock *block;
-
-       /* check for invalid flags at exit */
-       
-#ifdef TYPECHECK_DEBUG
-       for (block = state->basicblocks; block; block = block->next) {
-               if (block->flags != BBDELETED
-                       && block->flags != BBUNDEF
-                       && block->flags != BBFINISHED
-                       && block->flags != BBTYPECHECK_UNDEF) /* typecheck may never reach
-                                                                                                        * some exception handlers,
-                                                                                                        * that's ok. */
-               {
-                       LOG2("block L%03d has invalid flags after typecheck: %d",
-                                block->nr,block->flags);
-                       TYPECHECK_ASSERT(false);
-               }
-       }
-#endif
-       
-       /* Delete blocks we never reached */
-       
-       for (block = state->basicblocks; block; block = block->next) {
-               if (block->flags == BBTYPECHECK_UNDEF)
-                       block->flags = BBDELETED;
-       }
-}
-
-
-/****************************************************************************/
-/* TYPESTACK MACROS AND FUNCTIONS                                           */
-/*                                                                          */
-/* These macros and functions act on the 'type stack', which is a shorthand */
-/* for the types of the stackslots of the current stack. The type of a      */
-/* stack slot is usually described by a TYPE_* constant and -- for TYPE_ADR */
-/* -- by the typeinfo of the slot. The only thing that makes the type stack */
-/* more complicated are returnAddresses of local subroutines, because a     */
-/* single stack slot may contain a set of more than one possible return     */
-/* address. This is handled by 'return address sets'. A return address set  */
-/* is kept as a linked list dangling off the typeinfo of the stack slot.    */
-/****************************************************************************/
-
-/* typecheck_copy_types ********************************************************
-
-   Copy the types of the source variables to the destination variables.
-
-   IN:
-          state............current verifier state
-          srcvars..........array of variable indices to copy
-          dstvars..........array of the destination variables
-          n................number of variables to copy
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool typecheck_copy_types(verifier_state *state, s4 *srcvars, s4 *dstvars, s4 n)
-{
-       s4 i;
-       varinfo *sv;
-       varinfo *dv;
-       jitdata *jd = state->jd;
-
-       for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
-               sv = VAR(*srcvars);
-               dv = VAR(*dstvars);
-
-               dv->type = sv->type;
-               if (dv->type == TYPE_ADR) {
-                       TYPEINFO_CLONE(sv->typeinfo,dv->typeinfo);
-               }
-       }
-       return true;
-}
-
-
-/* typecheck_merge_types *******************************************************
-
-   Merge the types of the source variables into the destination variables.
-
-   IN:
-       state............current state of the verifier
-          srcvars..........source variable indices
-          dstvars..........destination variable indices
-          n................number of variables
-
-   RETURN VALUE:
-       typecheck_TRUE...the destination variables have been modified
-          typecheck_FALSE..the destination variables are unchanged
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result typecheck_merge_types(verifier_state *state,
-                                                                          s4 *srcvars,
-                                                                          s4 *dstvars,
-                                                                          s4 n)
-{
-       s4 i;
-       varinfo *sv;
-       varinfo *dv;
-       jitdata *jd = state->jd;
-       typecheck_result r;
-       bool changed = false;
-
-       for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
-               sv = VAR(*srcvars);
-               dv = VAR(*dstvars);
-
-               if (dv->type != sv->type) {
-                       exceptions_throw_verifyerror(state->m,"Stack type mismatch");
-                       return typecheck_FAIL;
-               }
-               if (dv->type == TYPE_ADR) {
-                       if (TYPEINFO_IS_PRIMITIVE(dv->typeinfo)) {
-                               /* dv has returnAddress type */
-                               if (!TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
-                                       exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
-                                       return typecheck_FAIL;
-                               }
-                       }
-                       else {
-                               /* dv has reference type */
-                               if (TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
-                                       exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
-                                       return typecheck_FAIL;
-                               }
-                               r = typeinfo_merge(state->m,&(dv->typeinfo),&(sv->typeinfo));
-                               if (r == typecheck_FAIL)
-                                       return r;
-                               changed |= r;
-                       }
-               }
-       }
-       return changed;
-}
-
-
-/* typestate_merge *************************************************************
-
-   Merge the types of one state into the destination state.
-
-   IN:
-       state............current state of the verifier
-          dstvars..........indices of the destinations invars
-          dstlocals........the destinations inlocals
-          srcvars..........indices of the source's outvars
-          srclocals........the source locals
-          n................number of invars (== number of outvars)
-
-   RETURN VALUE:
-       typecheck_TRUE...destination state has been modified
-          typecheck_FALSE..destination state has not been modified
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result typestate_merge(verifier_state *state,
-                                                s4 *srcvars, varinfo *srclocals,
-                                                s4 *dstvars, varinfo *dstlocals,
-                                                s4 n)
-{
-       bool changed = false;
-       typecheck_result r;
-
-       /* The stack is always merged. If there are returnAddresses on
-        * the stack they are ignored in this step. */
-
-       r = typecheck_merge_types(state, srcvars, dstvars, n);
-       if (r == typecheck_FAIL)
-               return r;
-       changed |= r;
-
-       /* merge the locals */
-
-       r = typevector_merge(state->m, dstlocals, srclocals, state->numlocals);
-       if (r == typecheck_FAIL)
-               return r;
-       return changed | r;
-}
-
-
-/* typestate_reach *************************************************************
-
-   Reach a destination block and propagate stack and local variable types
-
-   IN:
-       state............current state of the verifier
-          destblock........destination basic block
-          srcvars..........variable indices of the outvars to propagate
-          srclocals........local variables to propagate
-          n................number of srcvars
-
-   OUT:
-       state->repeat....set to true if the verifier must iterate again
-                           over the basic blocks
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool typestate_reach(verifier_state *state,
-                                        basicblock *destblock,
-                                        s4 *srcvars, varinfo *srclocals, s4 n)
-{
-       varinfo *destloc;
-       bool changed = false;
-       typecheck_result r;
-
-       LOG1("reaching block L%03d",destblock->nr);
-       TYPECHECK_COUNT(stat_reached);
-
-       destloc = destblock->inlocals;
-
-       if (destblock->flags == BBTYPECHECK_UNDEF) {
-               /* The destblock has never been reached before */
-
-               TYPECHECK_COUNT(stat_copied);
-               LOG1("block L%03d reached first time",destblock->nr);
-
-               if (!typecheck_copy_types(state, srcvars, destblock->invars, n))
-                       return false;
-               typevector_copy_inplace(srclocals, destloc, state->numlocals);
-               changed = true;
-       }
-       else {
-               /* The destblock has already been reached before */
-
-               TYPECHECK_COUNT(stat_merged);
-               LOG1("block L%03d reached before", destblock->nr);
-
-               r = typestate_merge(state, srcvars, srclocals,
-                               destblock->invars, destblock->inlocals, n);
-               if (r == typecheck_FAIL)
-                       return false;
-               changed = r;
-               TYPECHECK_COUNTIF(changed,stat_merging_changed);
-       }
-
-       if (changed) {
-               LOG("changed!");
-               destblock->flags = BBTYPECHECK_REACHED;
-               if (destblock->nr <= state->bptr->nr) {
-                       LOG("REPEAT!");
-                       state->repeat = true;
-               }
-       }
-       return true;
-}
-
-
-/* typecheck_init_locals *******************************************************
-
-   Initialize the local variables in the verifier state.
-
-   IN:
-       state............the current state of the verifier
-          newthis..........if true, mark the instance in <init> methods as
-                           uninitialized object.
-
-   RETURN VALUE:
-       true.............success,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-bool typecheck_init_locals(verifier_state *state, bool newthis)
-{
-       int i;
-       int varindex;
-       varinfo *locals;
-       varinfo *v;
-       jitdata *jd = state->jd;
-       int skip = 0;
-
-       locals = state->basicblocks[0].inlocals;
-
-       /* allocate parameter descriptors if necessary */
-
-       if (!state->m->parseddesc->params)
-               if (!descriptor_params_from_paramtypes(state->m->parseddesc,state->m->flags))
-                       return false;
-
-       /* pre-initialize variables as TYPE_VOID */
-
-       i = state->numlocals;
-       v = locals;
-       while (i--) {
-               v->type = TYPE_VOID;
-               v++;
-       }
-
-    /* if this is an instance method initialize the "this" ref type */
-
-    if (!(state->m->flags & ACC_STATIC)) {
-               varindex = jd->local_map[5*0 + TYPE_ADR];
-               if (varindex != UNUSED) {
-                       if (state->validlocals < 1)
-                               TYPECHECK_VERIFYERROR_bool("Not enough local variables for method arguments");
-                       v = locals + varindex;
-                       v->type = TYPE_ADR;
-                       if (state->initmethod && newthis)
-                               TYPEINFO_INIT_NEWOBJECT(v->typeinfo, NULL);
-                       else
-                               typeinfo_init_classinfo(&(v->typeinfo), state->m->clazz);
-               }
-
-               skip = 1;
-    }
-
-    LOG("'this' argument set.\n");
-
-    /* the rest of the arguments and the return type */
-
-    if (!typeinfo_init_varinfos_from_methoddesc(locals, state->m->parseddesc,
-                                                                                         state->validlocals,
-                                                                                         skip, /* skip 'this' pointer */
-                                                                                         jd->local_map,
-                                                                                         &state->returntype))
-               return false;
-
-    LOG("Arguments set.\n");
-       return true;
-}
-
-
-/*
- * 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/jit/verify/typecheck-common.cpp b/src/vm/jit/verify/typecheck-common.cpp
new file mode 100644 (file)
index 0000000..88f3861
--- /dev/null
@@ -0,0 +1,558 @@
+/* src/vm/jit/verify/typecheck-common.c - shared verifier code
+
+   Copyright (C) 1996-2005, 2006, 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 "vm/types.h"
+#include "vm/global.h"
+
+#include <assert.h>
+
+#include "vm/exceptions.hpp"
+#include "vm/globals.hpp"
+
+#include "vm/jit/show.hpp"
+
+#include "typecheck-common.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/****************************************************************************/
+/* DEBUG HELPERS                                                            */
+/****************************************************************************/
+
+#ifdef TYPECHECK_VERBOSE_OPT
+bool opt_typecheckverbose = false;
+#endif
+
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+
+void typecheck_print_var(FILE *file, jitdata *jd, s4 index)
+{
+       varinfo *var;
+
+       assert(index >= 0 && index < jd->varcount);
+       var = VAR(index);
+       typeinfo_print_type(file, var->type, &(var->typeinfo));
+}
+
+void typecheck_print_vararray(FILE *file, jitdata *jd, s4 *vars, int len)
+{
+       s4 i;
+
+       for (i=0; i<len; ++i) {
+               if (i)
+                       fputc(' ', file);
+               typecheck_print_var(file, jd, *vars++);
+       }
+}
+
+#endif /* defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT) */
+
+
+/****************************************************************************/
+/* STATISTICS                                                               */
+/****************************************************************************/
+
+#if defined(TYPECHECK_STATISTICS)
+int stat_typechecked = 0;
+int stat_methods_with_handlers = 0;
+int stat_methods_maythrow = 0;
+int stat_iterations[STAT_ITERATIONS+1] = { 0 };
+int stat_reached = 0;
+int stat_copied = 0;
+int stat_merged = 0;
+int stat_merging_changed = 0;
+int stat_blocks[STAT_BLOCKS+1] = { 0 };
+int stat_locals[STAT_LOCALS+1] = { 0 };
+int stat_ins = 0;
+int stat_ins_maythrow = 0;
+int stat_ins_stack = 0;
+int stat_ins_field = 0;
+int stat_ins_field_unresolved = 0;
+int stat_ins_field_uninitialized = 0;
+int stat_ins_invoke = 0;
+int stat_ins_invoke_unresolved = 0;
+int stat_ins_primload = 0;
+int stat_ins_aload = 0;
+int stat_ins_builtin = 0;
+int stat_ins_builtin_gen = 0;
+int stat_ins_branch = 0;
+int stat_ins_switch = 0;
+int stat_ins_primitive_return = 0;
+int stat_ins_areturn = 0;
+int stat_ins_areturn_unresolved = 0;
+int stat_ins_athrow = 0;
+int stat_ins_athrow_unresolved = 0;
+int stat_ins_unchecked = 0;
+int stat_handlers_reached = 0;
+int stat_savedstack = 0;
+
+static void print_freq(FILE *file,int *array,int limit)
+{
+       int i;
+       for (i=0; i<limit; ++i)
+               fprintf(file,"      %3d: %8d\n",i,array[i]);
+       fprintf(file,"    >=%3d: %8d\n",limit,array[limit]);
+}
+
+void typecheck_print_statistics(FILE *file) {
+       fprintf(file,"typechecked methods: %8d\n",stat_typechecked);
+       fprintf(file,"    with handler(s): %8d\n",stat_methods_with_handlers);
+       fprintf(file,"    with throw(s)  : %8d\n",stat_methods_maythrow);
+       fprintf(file,"reached blocks     : %8d\n",stat_reached);
+       fprintf(file,"copied states      : %8d\n",stat_copied);
+       fprintf(file,"merged states      : %8d\n",stat_merged);
+       fprintf(file,"merging changed    : %8d\n",stat_merging_changed);
+       fprintf(file,"handlers reached   : %8d\n",stat_handlers_reached);
+       fprintf(file,"saved stack (times): %8d\n",stat_savedstack);
+       fprintf(file,"instructions       : %8d\n",stat_ins);
+       fprintf(file,"    stack          : %8d\n",stat_ins_stack);
+       fprintf(file,"    field access   : %8d\n",stat_ins_field);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_field_unresolved);
+       fprintf(file,"      (uninit.)    : %8d\n",stat_ins_field_uninitialized);
+       fprintf(file,"    invocations    : %8d\n",stat_ins_invoke);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_invoke_unresolved);
+       fprintf(file,"    load primitive : (currently not counted) %8d\n",stat_ins_primload);
+       fprintf(file,"    load address   : %8d\n",stat_ins_aload);
+       fprintf(file,"    builtins       : %8d\n",stat_ins_builtin);
+       fprintf(file,"        generic    : %8d\n",stat_ins_builtin_gen);
+       fprintf(file,"    branches       : %8d\n",stat_ins_branch);
+       fprintf(file,"    switches       : %8d\n",stat_ins_switch);
+       fprintf(file,"    prim. return   : %8d\n",stat_ins_primitive_return);
+       fprintf(file,"    areturn        : %8d\n",stat_ins_areturn);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_areturn_unresolved);
+       fprintf(file,"    athrow         : %8d\n",stat_ins_athrow);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_athrow_unresolved);
+       fprintf(file,"    unchecked      : %8d\n",stat_ins_unchecked);
+       fprintf(file,"    maythrow       : %8d\n",stat_ins_maythrow);
+       fprintf(file,"iterations used:\n");
+       print_freq(file,stat_iterations,STAT_ITERATIONS);
+       fprintf(file,"basic blocks per method / 10:\n");
+       print_freq(file,stat_blocks,STAT_BLOCKS);
+       fprintf(file,"locals:\n");
+       print_freq(file,stat_locals,STAT_LOCALS);
+}
+#endif /* defined(TYPECHECK_STATISTICS) */
+
+
+/* typecheck_init_flags ********************************************************
+   Initialize the basic block flags for the following CFG traversal.
+  
+   IN:
+       state............the current state of the verifier
+       minflags.........minimum flags value of blocks that should be
+                        considered
+
+*******************************************************************************/
+
+void typecheck_init_flags(verifier_state *state, s4 minflags)
+{
+       basicblock *block;
+
+    /* set all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
+       
+    for (block = state->basicblocks; block; block = block->next) {
+               
+#ifdef TYPECHECK_DEBUG
+               /* check for invalid flags */
+        if (block->flags != BBFINISHED && block->flags != BBDELETED && block->flags != BBUNDEF)
+        {
+            LOGSTR1("block flags: %d\n",block->flags); LOGFLUSH;
+                       TYPECHECK_ASSERT(false);
+        }
+#endif
+
+        if (block->flags >= minflags) {
+            block->flags = BBTYPECHECK_UNDEF;
+        }
+    }
+
+    /* the first block is always reached */
+       
+    if (state->basicblockcount && state->basicblocks[0].flags == BBTYPECHECK_UNDEF)
+        state->basicblocks[0].flags = BBTYPECHECK_REACHED;
+}
+
+
+/* typecheck_reset_flags *******************************************************
+   Reset the flags of basic blocks we have not reached.
+  
+   IN:
+       state............the current state of the verifier
+
+*******************************************************************************/
+
+void typecheck_reset_flags(verifier_state *state)
+{
+       basicblock *block;
+
+       /* check for invalid flags at exit */
+       
+#ifdef TYPECHECK_DEBUG
+       for (block = state->basicblocks; block; block = block->next) {
+               if (block->flags != BBDELETED
+                       && block->flags != BBUNDEF
+                       && block->flags != BBFINISHED
+                       && block->flags != BBTYPECHECK_UNDEF) /* typecheck may never reach
+                                                                                                        * some exception handlers,
+                                                                                                        * that's ok. */
+               {
+                       LOG2("block L%03d has invalid flags after typecheck: %d",
+                                block->nr,block->flags);
+                       TYPECHECK_ASSERT(false);
+               }
+       }
+#endif
+       
+       /* Delete blocks we never reached */
+       
+       for (block = state->basicblocks; block; block = block->next) {
+               if (block->flags == BBTYPECHECK_UNDEF)
+                       block->flags = BBDELETED;
+       }
+}
+
+
+/****************************************************************************/
+/* TYPESTACK MACROS AND FUNCTIONS                                           */
+/*                                                                          */
+/* These macros and functions act on the 'type stack', which is a shorthand */
+/* for the types of the stackslots of the current stack. The type of a      */
+/* stack slot is usually described by a TYPE_* constant and -- for TYPE_ADR */
+/* -- by the typeinfo of the slot. The only thing that makes the type stack */
+/* more complicated are returnAddresses of local subroutines, because a     */
+/* single stack slot may contain a set of more than one possible return     */
+/* address. This is handled by 'return address sets'. A return address set  */
+/* is kept as a linked list dangling off the typeinfo of the stack slot.    */
+/****************************************************************************/
+
+/* typecheck_copy_types ********************************************************
+
+   Copy the types of the source variables to the destination variables.
+
+   IN:
+          state............current verifier state
+          srcvars..........array of variable indices to copy
+          dstvars..........array of the destination variables
+          n................number of variables to copy
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool typecheck_copy_types(verifier_state *state, s4 *srcvars, s4 *dstvars, s4 n)
+{
+       s4 i;
+       varinfo *sv;
+       varinfo *dv;
+       jitdata *jd = state->jd;
+
+       for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
+               sv = VAR(*srcvars);
+               dv = VAR(*dstvars);
+
+               dv->type = sv->type;
+               if (dv->type == TYPE_ADR) {
+                       TYPEINFO_CLONE(sv->typeinfo,dv->typeinfo);
+               }
+       }
+       return true;
+}
+
+
+/* typecheck_merge_types *******************************************************
+
+   Merge the types of the source variables into the destination variables.
+
+   IN:
+       state............current state of the verifier
+          srcvars..........source variable indices
+          dstvars..........destination variable indices
+          n................number of variables
+
+   RETURN VALUE:
+       typecheck_TRUE...the destination variables have been modified
+          typecheck_FALSE..the destination variables are unchanged
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result typecheck_merge_types(verifier_state *state,
+                                                                          s4 *srcvars,
+                                                                          s4 *dstvars,
+                                                                          s4 n)
+{
+       s4 i;
+       varinfo *sv;
+       varinfo *dv;
+       jitdata *jd = state->jd;
+       typecheck_result r;
+       bool changed = false;
+
+       for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
+               sv = VAR(*srcvars);
+               dv = VAR(*dstvars);
+
+               if (dv->type != sv->type) {
+                       exceptions_throw_verifyerror(state->m,"Stack type mismatch");
+                       return typecheck_FAIL;
+               }
+               if (dv->type == TYPE_ADR) {
+                       if (TYPEINFO_IS_PRIMITIVE(dv->typeinfo)) {
+                               /* dv has returnAddress type */
+                               if (!TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
+                                       exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
+                                       return typecheck_FAIL;
+                               }
+                       }
+                       else {
+                               /* dv has reference type */
+                               if (TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
+                                       exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
+                                       return typecheck_FAIL;
+                               }
+                               r = typeinfo_merge(state->m,&(dv->typeinfo),&(sv->typeinfo));
+                               if (r == typecheck_FAIL)
+                                       return r;
+                               changed |= r;
+                       }
+               }
+       }
+       return (typecheck_result) changed;
+}
+
+
+/* typestate_merge *************************************************************
+
+   Merge the types of one state into the destination state.
+
+   IN:
+       state............current state of the verifier
+          dstvars..........indices of the destinations invars
+          dstlocals........the destinations inlocals
+          srcvars..........indices of the source's outvars
+          srclocals........the source locals
+          n................number of invars (== number of outvars)
+
+   RETURN VALUE:
+       typecheck_TRUE...destination state has been modified
+          typecheck_FALSE..destination state has not been modified
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result typestate_merge(verifier_state *state,
+                                                s4 *srcvars, varinfo *srclocals,
+                                                s4 *dstvars, varinfo *dstlocals,
+                                                s4 n)
+{
+       bool changed = false;
+       typecheck_result r;
+
+       /* The stack is always merged. If there are returnAddresses on
+        * the stack they are ignored in this step. */
+
+       r = typecheck_merge_types(state, srcvars, dstvars, n);
+       if (r == typecheck_FAIL)
+               return r;
+       changed |= r;
+
+       /* merge the locals */
+
+       r = typevector_merge(state->m, dstlocals, srclocals, state->numlocals);
+       if (r == typecheck_FAIL)
+               return r;
+       return (typecheck_result) (changed | r);
+}
+
+
+/* typestate_reach *************************************************************
+
+   Reach a destination block and propagate stack and local variable types
+
+   IN:
+       state............current state of the verifier
+          destblock........destination basic block
+          srcvars..........variable indices of the outvars to propagate
+          srclocals........local variables to propagate
+          n................number of srcvars
+
+   OUT:
+       state->repeat....set to true if the verifier must iterate again
+                           over the basic blocks
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool typestate_reach(verifier_state *state,
+                                        basicblock *destblock,
+                                        s4 *srcvars, varinfo *srclocals, s4 n)
+{
+       varinfo *destloc;
+       bool changed = false;
+       typecheck_result r;
+
+       LOG1("reaching block L%03d",destblock->nr);
+       TYPECHECK_COUNT(stat_reached);
+
+       destloc = destblock->inlocals;
+
+       if (destblock->flags == BBTYPECHECK_UNDEF) {
+               /* The destblock has never been reached before */
+
+               TYPECHECK_COUNT(stat_copied);
+               LOG1("block L%03d reached first time",destblock->nr);
+
+               if (!typecheck_copy_types(state, srcvars, destblock->invars, n))
+                       return false;
+               typevector_copy_inplace(srclocals, destloc, state->numlocals);
+               changed = true;
+       }
+       else {
+               /* The destblock has already been reached before */
+
+               TYPECHECK_COUNT(stat_merged);
+               LOG1("block L%03d reached before", destblock->nr);
+
+               r = typestate_merge(state, srcvars, srclocals,
+                               destblock->invars, destblock->inlocals, n);
+               if (r == typecheck_FAIL)
+                       return false;
+               changed = r;
+               TYPECHECK_COUNTIF(changed,stat_merging_changed);
+       }
+
+       if (changed) {
+               LOG("changed!");
+               destblock->flags = BBTYPECHECK_REACHED;
+               if (destblock->nr <= state->bptr->nr) {
+                       LOG("REPEAT!");
+                       state->repeat = true;
+               }
+       }
+       return true;
+}
+
+
+/* typecheck_init_locals *******************************************************
+
+   Initialize the local variables in the verifier state.
+
+   IN:
+       state............the current state of the verifier
+          newthis..........if true, mark the instance in <init> methods as
+                           uninitialized object.
+
+   RETURN VALUE:
+       true.............success,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+bool typecheck_init_locals(verifier_state *state, bool newthis)
+{
+       int i;
+       int varindex;
+       varinfo *locals;
+       varinfo *v;
+       jitdata *jd = state->jd;
+       int skip = 0;
+
+       locals = state->basicblocks[0].inlocals;
+
+       /* allocate parameter descriptors if necessary */
+
+       if (!state->m->parseddesc->params)
+               if (!descriptor_params_from_paramtypes(state->m->parseddesc,state->m->flags))
+                       return false;
+
+       /* pre-initialize variables as TYPE_VOID */
+
+       i = state->numlocals;
+       v = locals;
+       while (i--) {
+               v->type = TYPE_VOID;
+               v++;
+       }
+
+    /* if this is an instance method initialize the "this" ref type */
+
+    if (!(state->m->flags & ACC_STATIC)) {
+               varindex = jd->local_map[5*0 + TYPE_ADR];
+               if (varindex != UNUSED) {
+                       if (state->validlocals < 1)
+                               TYPECHECK_VERIFYERROR_bool("Not enough local variables for method arguments");
+                       v = locals + varindex;
+                       v->type = TYPE_ADR;
+                       if (state->initmethod && newthis)
+                               TYPEINFO_INIT_NEWOBJECT(v->typeinfo, NULL);
+                       else
+                               typeinfo_init_classinfo(&(v->typeinfo), state->m->clazz);
+               }
+
+               skip = 1;
+    }
+
+    LOG("'this' argument set.\n");
+
+    /* the rest of the arguments and the return type */
+
+    if (!typeinfo_init_varinfos_from_methoddesc(locals, state->m->parseddesc,
+                                                                                         state->validlocals,
+                                                                                         skip, /* skip 'this' pointer */
+                                                                                         jd->local_map,
+                                                                                         &state->returntype))
+               return false;
+
+    LOG("Arguments set.\n");
+       return true;
+}
+
+#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/jit/verify/typecheck-common.h b/src/vm/jit/verify/typecheck-common.h
deleted file mode 100644 (file)
index 226113f..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/* src/vm/jit/verify/typecheck-common.h - internal header for the type checker
-
-   Copyright (C) 1996-2005, 2006, 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 _TYPECHECK_COMMON_H
-#define _TYPECHECK_COMMON_H
-
-#include "config.h"
-#include "vm/types.h"
-#include "vm/global.h"
-
-#include <assert.h>
-
-#include "vm/jit/jit.hpp"
-
-
-/****************************************************************************/
-/* DEBUG HELPERS                                                            */
-/****************************************************************************/
-
-#ifdef TYPECHECK_DEBUG
-#define TYPECHECK_ASSERT(cond)  assert(cond)
-#else
-#define TYPECHECK_ASSERT(cond)
-#endif
-
-#ifdef TYPECHECK_VERBOSE_OPT
-extern bool opt_typecheckverbose;
-#define DOLOG(action)  do { if (opt_typecheckverbose) {action;} } while(0)
-#else
-#define DOLOG(action)
-#endif
-
-#ifdef TYPECHECK_VERBOSE
-#define TYPECHECK_VERBOSE_IMPORTANT
-#define LOGNL              DOLOG(puts(""))
-#define LOG(str)           DOLOG(puts(str);)
-#define LOG1(str,a)        DOLOG(printf(str,a); LOGNL)
-#define LOG2(str,a,b)      DOLOG(printf(str,a,b); LOGNL)
-#define LOG3(str,a,b,c)    DOLOG(printf(str,a,b,c); LOGNL)
-#define LOGIF(cond,str)    DOLOG(do {if (cond) { puts(str); }} while(0))
-#ifdef  TYPEINFO_DEBUG
-#define LOGINFO(info)      DOLOG(do {typeinfo_print_short(stdout,(info)); LOGNL;} while(0))
-#else
-#define LOGINFO(info)
-#define typevector_print(x,y,z)
-#endif
-#define LOGFLUSH           DOLOG(fflush(stdout))
-#define LOGSTR(str)        DOLOG(printf("%s", str))
-#define LOGSTR1(str,a)     DOLOG(printf(str,a))
-#define LOGSTR2(str,a,b)   DOLOG(printf(str,a,b))
-#define LOGSTR3(str,a,b,c) DOLOG(printf(str,a,b,c))
-#define LOGNAME(c)         DOLOG(class_classref_or_classinfo_print(c))
-#define LOGMETHOD(str,m)   DOLOG(printf("%s", str); method_println(m);)
-#else
-#define LOG(str)
-#define LOG1(str,a)
-#define LOG2(str,a,b)
-#define LOG3(str,a,b,c)
-#define LOGIF(cond,str)
-#define LOGINFO(info)
-#define LOGFLUSH
-#define LOGNL
-#define LOGSTR(str)
-#define LOGSTR1(str,a)
-#define LOGSTR2(str,a,b)
-#define LOGSTR3(str,a,b,c)
-#define LOGNAME(c)
-#define LOGMETHOD(str,m)
-#endif
-
-#ifdef TYPECHECK_VERBOSE_IMPORTANT
-#define LOGimp(str)     DOLOG(puts(str);LOGNL)
-#define LOGimpSTR(str)  DOLOG(puts(str))
-#else
-#define LOGimp(str)
-#define LOGimpSTR(str)
-#endif
-
-#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
-#include <stdio.h>
-void typecheck_print_var(FILE *file, jitdata *jd, s4 index);
-void typecheck_print_vararray(FILE *file, jitdata *jd, s4 *vars, int len);
-#endif
-
-
-/****************************************************************************/
-/* STATISTICS                                                               */
-/****************************************************************************/
-
-#if defined(TYPECHECK_DEBUG) && !defined(TYPECHECK_NO_STATISTICS)
-/*#define TYPECHECK_STATISTICS*/
-#endif
-
-#ifdef TYPECHECK_STATISTICS
-#define STAT_ITERATIONS  10
-#define STAT_BLOCKS      10
-#define STAT_LOCALS      16
-
-extern int stat_typechecked;
-extern int stat_methods_with_handlers;
-extern int stat_methods_maythrow;
-extern int stat_iterations[STAT_ITERATIONS+1];
-extern int stat_reached;
-extern int stat_copied;
-extern int stat_merged;
-extern int stat_merging_changed;
-extern int stat_blocks[STAT_BLOCKS+1];
-extern int stat_locals[STAT_LOCALS+1];
-extern int stat_ins;
-extern int stat_ins_maythrow;
-extern int stat_ins_stack;
-extern int stat_ins_field;
-extern int stat_ins_field_unresolved;
-extern int stat_ins_field_uninitialized;
-extern int stat_ins_invoke;
-extern int stat_ins_invoke_unresolved;
-extern int stat_ins_primload;
-extern int stat_ins_aload;
-extern int stat_ins_builtin;
-extern int stat_ins_builtin_gen;
-extern int stat_ins_branch;
-extern int stat_ins_switch;
-extern int stat_ins_primitive_return;
-extern int stat_ins_areturn;
-extern int stat_ins_areturn_unresolved;
-extern int stat_ins_athrow;
-extern int stat_ins_athrow_unresolved;
-extern int stat_ins_unchecked;
-extern int stat_handlers_reached;
-extern int stat_savedstack;
-
-#define TYPECHECK_MARK(var)   ((var) = true)
-#define TYPECHECK_COUNT(cnt)  (cnt)++
-#define TYPECHECK_COUNTIF(cond,cnt)  do{if(cond) (cnt)++;} while(0)
-#define TYPECHECK_COUNT_FREQ(array,val,limit) \
-       do {                                                                      \
-               if ((val) < (limit)) (array)[val]++;  \
-               else (array)[limit]++;                            \
-       } while (0)
-
-void typecheck_print_statistics(FILE *file);
-
-#else /* !defined(TYPECHECK_STATISTICS) */
-                                                  
-#define TYPECHECK_COUNT(cnt)
-#define TYPECHECK_MARK(var)
-#define TYPECHECK_COUNTIF(cond,cnt)
-#define TYPECHECK_COUNT_FREQ(array,val,limit)
-
-#endif /* defined(TYPECHECK_STATISTICS) */
-
-
-/****************************************************************************/
-/* MACROS FOR THROWING EXCEPTIONS                                           */
-/****************************************************************************/
-
-#define TYPECHECK_VERIFYERROR_ret(m,msg,retval)                      \
-    do {                                                             \
-        exceptions_throw_verifyerror((m), (msg));                    \
-        return (retval);                                             \
-    } while (0)
-
-#define TYPECHECK_VERIFYERROR_main(msg)  TYPECHECK_VERIFYERROR_ret(state.m,(msg),NULL)
-#define TYPECHECK_VERIFYERROR_bool(msg)  TYPECHECK_VERIFYERROR_ret(state->m,(msg),false)
-
-
-/****************************************************************************/
-/* MISC MACROS                                                              */
-/****************************************************************************/
-
-#define COPYTYPE(source,dest)                                        \
-    {if (VAROP(source)->type == TYPE_ADR)                            \
-            TYPEINFO_COPY(VAROP(source)->typeinfo,VAROP(dest)->typeinfo);}
-
-
-/****************************************************************************/
-/* JSR VERIFICATION (stack-based verifier)                                  */
-/****************************************************************************/
-
-typedef struct typecheck_jsr_t typecheck_jsr_t;
-typedef struct typecheck_jsr_caller_t typecheck_jsr_caller_t;
-
-struct typecheck_jsr_caller_t {
-       typecheck_jsr_caller_t *next;                   /* next in linked list */
-       basicblock *callblock;             /* block containing the calling JSR */
-};
-
-struct typecheck_jsr_t {
-       typecheck_jsr_t *next;               /* next (lower) in the call chain */
-       basicblock  *start;                                   /* for debugging */
-       typecheck_jsr_caller_t *callers;  /* list of callers (blocks with JSR) */
-       basicblock  *retblock;              /* block with the RET for this sub */
-       bool         active;           /* true if this sub is currently active */
-       char        *blockflags;   /* saved block flags when JSR was traversed */
-       char        *usedlocals;       /* != 0 for each local used in this sub */
-       typedescriptor_t *retlocals;                 /* locals on the RET edge */
-       typedescriptor_t *retstack;                   /* stack on the RET edge */
-       s4              retdepth;               /* stack depth on the RET edge */
-};
-
-/****************************************************************************/
-/* VERIFIER STATE STRUCT                                                    */
-/****************************************************************************/
-
-/* verifier_state - This structure keeps the current state of the      */
-/* bytecode verifier for passing it between verifier functions.        */
-
-typedef struct verifier_state {
-    instruction *iptr;               /* pointer to current instruction */
-    basicblock *bptr;                /* pointer to current basic block */
-
-       methodinfo *m;                               /* the current method */
-       jitdata *jd;                         /* jitdata for current method */
-       codegendata *cd;                 /* codegendata for current method */
-
-       basicblock *basicblocks;
-       s4 basicblockcount;
-       
-       s4 numlocals;                         /* number of local variables */
-       s4 validlocals;                /* number of Java-accessible locals */
-       
-       typedescriptor_t returntype;  /* return type of the current method */
-
-       s4 *savedindices;
-       s4 *savedinvars;                            /* saved invar pointer */
-
-       s4 exinvars;
-       
-    exception_entry **handlers;           /* active exception handlers */
-       
-    bool repeat;            /* if true, blocks are iterated over again */
-    bool initmethod;             /* true if this is an "<init>" method */
-
-#ifdef TYPECHECK_STATISTICS
-       bool stat_maythrow;          /* at least one instruction may throw */
-#endif
-
-       /* the following fields are used by the stackbased verifier only:  */
-
-       typedescriptor_t *locals;               /* current local variables */
-       typedescriptor_t *startlocals;/* locals at the start of each block */
-       typedescriptor_t *startstack;  /* stack at the start of each block */
-       s4               *indepth;                /* stack depth at --''-- */
-       typedescriptor_t *stackceiling;    /* upper edge of verifier stack */
-
-       typecheck_jsr_t *topjsr;        /* most recently called subroutine */
-       typecheck_jsr_t **jsrinfos;      /* subroutine info for each block */
-} verifier_state;
-
-void typecheck_init_flags(verifier_state *state, s4 minflags);
-void typecheck_reset_flags(verifier_state *state);
-
-bool typecheck_copy_types(verifier_state *state,
-                                                 s4 *srcvars, s4 *dstvars, s4 n);
-
-typecheck_result typecheck_merge_types(verifier_state *state,
-                                                                          s4 *srcvars,
-                                                                          s4 *dstvars,
-                                                                          s4 n);
-
-typecheck_result typestate_merge(verifier_state *state,
-                                                s4 *srcvars, varinfo *srclocals,
-                                                s4 *dstvars, varinfo *dstlocals,
-                                                s4 n);
-
-bool typestate_reach(verifier_state *state,
-                                        basicblock *destblock,
-                                        s4 *srcvars, varinfo *srclocals, s4 n);
-
-bool typecheck_init_locals(verifier_state *state, bool newthis);
-
-#endif /* _TYPECHECK_COMMON_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/jit/verify/typecheck-common.hpp b/src/vm/jit/verify/typecheck-common.hpp
new file mode 100644 (file)
index 0000000..f6cb2e4
--- /dev/null
@@ -0,0 +1,315 @@
+/* src/vm/jit/verify/typecheck-common.h - internal header for the type checker
+
+   Copyright (C) 1996-2005, 2006, 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 _TYPECHECK_COMMON_H
+#define _TYPECHECK_COMMON_H
+
+#include "config.h"
+#include "vm/types.h"
+#include "vm/global.h"
+
+#include <assert.h>
+
+#include "vm/jit/jit.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/****************************************************************************/
+/* DEBUG HELPERS                                                            */
+/****************************************************************************/
+
+#ifdef TYPECHECK_DEBUG
+#define TYPECHECK_ASSERT(cond)  assert(cond)
+#else
+#define TYPECHECK_ASSERT(cond)
+#endif
+
+#ifdef TYPECHECK_VERBOSE_OPT
+extern bool opt_typecheckverbose;
+#define DOLOG(action)  do { if (opt_typecheckverbose) {action;} } while(0)
+#else
+#define DOLOG(action)
+#endif
+
+#ifdef TYPECHECK_VERBOSE
+#define TYPECHECK_VERBOSE_IMPORTANT
+#define LOGNL              DOLOG(puts(""))
+#define LOG(str)           DOLOG(puts(str);)
+#define LOG1(str,a)        DOLOG(printf(str,a); LOGNL)
+#define LOG2(str,a,b)      DOLOG(printf(str,a,b); LOGNL)
+#define LOG3(str,a,b,c)    DOLOG(printf(str,a,b,c); LOGNL)
+#define LOGIF(cond,str)    DOLOG(do {if (cond) { puts(str); }} while(0))
+#ifdef  TYPEINFO_DEBUG
+#define LOGINFO(info)      DOLOG(do {typeinfo_print_short(stdout,(info)); LOGNL;} while(0))
+#else
+#define LOGINFO(info)
+#define typevector_print(x,y,z)
+#endif
+#define LOGFLUSH           DOLOG(fflush(stdout))
+#define LOGSTR(str)        DOLOG(printf("%s", str))
+#define LOGSTR1(str,a)     DOLOG(printf(str,a))
+#define LOGSTR2(str,a,b)   DOLOG(printf(str,a,b))
+#define LOGSTR3(str,a,b,c) DOLOG(printf(str,a,b,c))
+#define LOGNAME(c)         DOLOG(class_classref_or_classinfo_print(c))
+#define LOGMETHOD(str,m)   DOLOG(printf("%s", str); method_println(m);)
+#else
+#define LOG(str)
+#define LOG1(str,a)
+#define LOG2(str,a,b)
+#define LOG3(str,a,b,c)
+#define LOGIF(cond,str)
+#define LOGINFO(info)
+#define LOGFLUSH
+#define LOGNL
+#define LOGSTR(str)
+#define LOGSTR1(str,a)
+#define LOGSTR2(str,a,b)
+#define LOGSTR3(str,a,b,c)
+#define LOGNAME(c)
+#define LOGMETHOD(str,m)
+#endif
+
+#ifdef TYPECHECK_VERBOSE_IMPORTANT
+#define LOGimp(str)     DOLOG(puts(str);LOGNL)
+#define LOGimpSTR(str)  DOLOG(puts(str))
+#else
+#define LOGimp(str)
+#define LOGimpSTR(str)
+#endif
+
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+#include <stdio.h>
+void typecheck_print_var(FILE *file, jitdata *jd, s4 index);
+void typecheck_print_vararray(FILE *file, jitdata *jd, s4 *vars, int len);
+#endif
+
+
+/****************************************************************************/
+/* STATISTICS                                                               */
+/****************************************************************************/
+
+#if defined(TYPECHECK_DEBUG) && !defined(TYPECHECK_NO_STATISTICS)
+/*#define TYPECHECK_STATISTICS*/
+#endif
+
+#ifdef TYPECHECK_STATISTICS
+#define STAT_ITERATIONS  10
+#define STAT_BLOCKS      10
+#define STAT_LOCALS      16
+
+extern int stat_typechecked;
+extern int stat_methods_with_handlers;
+extern int stat_methods_maythrow;
+extern int stat_iterations[STAT_ITERATIONS+1];
+extern int stat_reached;
+extern int stat_copied;
+extern int stat_merged;
+extern int stat_merging_changed;
+extern int stat_blocks[STAT_BLOCKS+1];
+extern int stat_locals[STAT_LOCALS+1];
+extern int stat_ins;
+extern int stat_ins_maythrow;
+extern int stat_ins_stack;
+extern int stat_ins_field;
+extern int stat_ins_field_unresolved;
+extern int stat_ins_field_uninitialized;
+extern int stat_ins_invoke;
+extern int stat_ins_invoke_unresolved;
+extern int stat_ins_primload;
+extern int stat_ins_aload;
+extern int stat_ins_builtin;
+extern int stat_ins_builtin_gen;
+extern int stat_ins_branch;
+extern int stat_ins_switch;
+extern int stat_ins_primitive_return;
+extern int stat_ins_areturn;
+extern int stat_ins_areturn_unresolved;
+extern int stat_ins_athrow;
+extern int stat_ins_athrow_unresolved;
+extern int stat_ins_unchecked;
+extern int stat_handlers_reached;
+extern int stat_savedstack;
+
+#define TYPECHECK_MARK(var)   ((var) = true)
+#define TYPECHECK_COUNT(cnt)  (cnt)++
+#define TYPECHECK_COUNTIF(cond,cnt)  do{if(cond) (cnt)++;} while(0)
+#define TYPECHECK_COUNT_FREQ(array,val,limit) \
+       do {                                                                      \
+               if ((val) < (limit)) (array)[val]++;  \
+               else (array)[limit]++;                            \
+       } while (0)
+
+void typecheck_print_statistics(FILE *file);
+
+#else /* !defined(TYPECHECK_STATISTICS) */
+                                                  
+#define TYPECHECK_COUNT(cnt)
+#define TYPECHECK_MARK(var)
+#define TYPECHECK_COUNTIF(cond,cnt)
+#define TYPECHECK_COUNT_FREQ(array,val,limit)
+
+#endif /* defined(TYPECHECK_STATISTICS) */
+
+
+/****************************************************************************/
+/* MACROS FOR THROWING EXCEPTIONS                                           */
+/****************************************************************************/
+
+#define TYPECHECK_VERIFYERROR_ret(m,msg,retval)                      \
+    do {                                                             \
+        exceptions_throw_verifyerror((m), (msg));                    \
+        return (retval);                                             \
+    } while (0)
+
+#define TYPECHECK_VERIFYERROR_main(msg)  TYPECHECK_VERIFYERROR_ret(state.m,(msg),NULL)
+#define TYPECHECK_VERIFYERROR_bool(msg)  TYPECHECK_VERIFYERROR_ret(state->m,(msg),false)
+
+
+/****************************************************************************/
+/* MISC MACROS                                                              */
+/****************************************************************************/
+
+#define COPYTYPE(source,dest)                                        \
+    {if (VAROP(source)->type == TYPE_ADR)                            \
+            TYPEINFO_COPY(VAROP(source)->typeinfo,VAROP(dest)->typeinfo);}
+
+
+/****************************************************************************/
+/* JSR VERIFICATION (stack-based verifier)                                  */
+/****************************************************************************/
+
+typedef struct typecheck_jsr_t typecheck_jsr_t;
+typedef struct typecheck_jsr_caller_t typecheck_jsr_caller_t;
+
+struct typecheck_jsr_caller_t {
+       typecheck_jsr_caller_t *next;                   /* next in linked list */
+       basicblock *callblock;             /* block containing the calling JSR */
+};
+
+struct typecheck_jsr_t {
+       typecheck_jsr_t *next;               /* next (lower) in the call chain */
+       basicblock  *start;                                   /* for debugging */
+       typecheck_jsr_caller_t *callers;  /* list of callers (blocks with JSR) */
+       basicblock  *retblock;              /* block with the RET for this sub */
+       bool         active;           /* true if this sub is currently active */
+       char        *blockflags;   /* saved block flags when JSR was traversed */
+       char        *usedlocals;       /* != 0 for each local used in this sub */
+       typedescriptor_t *retlocals;                 /* locals on the RET edge */
+       typedescriptor_t *retstack;                   /* stack on the RET edge */
+       s4              retdepth;               /* stack depth on the RET edge */
+};
+
+/****************************************************************************/
+/* VERIFIER STATE STRUCT                                                    */
+/****************************************************************************/
+
+/* verifier_state - This structure keeps the current state of the      */
+/* bytecode verifier for passing it between verifier functions.        */
+
+typedef struct verifier_state {
+    instruction *iptr;               /* pointer to current instruction */
+    basicblock *bptr;                /* pointer to current basic block */
+
+       methodinfo *m;                               /* the current method */
+       jitdata *jd;                         /* jitdata for current method */
+       codegendata *cd;                 /* codegendata for current method */
+
+       basicblock *basicblocks;
+       s4 basicblockcount;
+       
+       s4 numlocals;                         /* number of local variables */
+       s4 validlocals;                /* number of Java-accessible locals */
+       
+       typedescriptor_t returntype;  /* return type of the current method */
+
+       s4 *savedindices;
+       s4 *savedinvars;                            /* saved invar pointer */
+
+       s4 exinvars;
+       
+    exception_entry **handlers;           /* active exception handlers */
+       
+    bool repeat;            /* if true, blocks are iterated over again */
+    bool initmethod;             /* true if this is an "<init>" method */
+
+#ifdef TYPECHECK_STATISTICS
+       bool stat_maythrow;          /* at least one instruction may throw */
+#endif
+
+       /* the following fields are used by the stackbased verifier only:  */
+
+       typedescriptor_t *locals;               /* current local variables */
+       typedescriptor_t *startlocals;/* locals at the start of each block */
+       typedescriptor_t *startstack;  /* stack at the start of each block */
+       s4               *indepth;                /* stack depth at --''-- */
+       typedescriptor_t *stackceiling;    /* upper edge of verifier stack */
+
+       typecheck_jsr_t *topjsr;        /* most recently called subroutine */
+       typecheck_jsr_t **jsrinfos;      /* subroutine info for each block */
+} verifier_state;
+
+void typecheck_init_flags(verifier_state *state, s4 minflags);
+void typecheck_reset_flags(verifier_state *state);
+
+bool typecheck_copy_types(verifier_state *state,
+                                                 s4 *srcvars, s4 *dstvars, s4 n);
+
+typecheck_result typecheck_merge_types(verifier_state *state,
+                                                                          s4 *srcvars,
+                                                                          s4 *dstvars,
+                                                                          s4 n);
+
+typecheck_result typestate_merge(verifier_state *state,
+                                                s4 *srcvars, varinfo *srclocals,
+                                                s4 *dstvars, varinfo *dstlocals,
+                                                s4 n);
+
+bool typestate_reach(verifier_state *state,
+                                        basicblock *destblock,
+                                        s4 *srcvars, varinfo *srclocals, s4 n);
+
+bool typecheck_init_locals(verifier_state *state, bool newthis);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _TYPECHECK_COMMON_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/jit/verify/typecheck-stackbased.c b/src/vm/jit/verify/typecheck-stackbased.c
deleted file mode 100644 (file)
index b978516..0000000
+++ /dev/null
@@ -1,1027 +0,0 @@
-/* src/vm/jit/verify/typecheck-stackbased.c - stack-based verifier
-
-   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 "vm/jit/builtin.hpp"
-#include "mm/memory.h"
-
-#include "vm/array.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/global.h"
-#include "vm/globals.hpp"
-#include "vm/primitive.hpp"
-
-#include "vm/jit/parse.h"
-#include "vm/jit/show.hpp"
-#include "vm/jit/stack.h"
-#include "vm/jit/verify/typecheck-common.h"
-
-
-/* this #if runs over the whole file: */
-#if defined(ENABLE_VERIFIER)
-
-typedef typedescriptor_t verifier_slot_t;
-
-#if defined(TYPECHECK_VERBOSE)
-static void typecheck_stackbased_show_state(verifier_state *state,
-                                                                                       typedescriptor *stack,
-                                                                                       typedescriptor *stackfloor,
-                                                                                       bool showins);
-#endif
-
-
-#define CHECK_STACK_DEPTH(d)                                         \
-    if (((u1*)stack - (u1*)stackfloor)                               \
-            < (((d)-1) * (int)sizeof(verifier_slot_t)))              \
-        goto throw_stack_underflow;
-
-/* XXX don't need to check against ACONST for every ICMD */
-#define CHECK_STACK_SPACE(d)                                         \
-    if (((u1*)STATE->stackceiling - (u1*)stack)                      \
-            < (((d)+1) * (int)sizeof(verifier_slot_t)))              \
-        if (STATE->iptr->opc != ICMD_ACONST                          \
-                || INSTRUCTION_MUST_CHECK(STATE->iptr))              \
-            goto throw_stack_overflow;
-
-#define CHECK_STACK_TYPE(s, t)                                       \
-    if ((s).type != (t))                                             \
-        goto throw_stack_type_error;
-
-/* XXX inefficient */
-#define CHECK_LOCAL_TYPE(index, t)                                   \
-    do {                                                             \
-        if (state.locals[(index)].type != (t))                       \
-            goto throw_local_type_error;                             \
-        if (STATE->topjsr)                                           \
-            STATE->topjsr->usedlocals[(index)] = 1;                  \
-        if (STATE->topjsr && IS_2_WORD_TYPE(t))                      \
-            STATE->topjsr->usedlocals[(index) + 1] = 1;              \
-    } while(0)
-
-/* XXX inefficient */
-#define STORE_LOCAL(t, index)                                        \
-    do {                                                             \
-        state.locals[(index)].type = (t);                            \
-        if ((index) && IS_2_WORD_TYPE(state.locals[(index)-1].type)) \
-            state.locals[(index-1)].type = TYPE_VOID;                \
-        if (STATE->topjsr)                                           \
-            STATE->topjsr->usedlocals[(index)] = 1;                  \
-    } while (0)
-
-/* XXX inefficient */
-#define STORE_LOCAL_2_WORD(t, index)                                 \
-    do {                                                             \
-        STORE_LOCAL(t, index);                                       \
-        state.locals[(index)+1].type = TYPE_VOID;                    \
-        if (STATE->topjsr)                                           \
-            STATE->topjsr->usedlocals[(index)] = 1;                  \
-    } while (0)
-
-#define VERIFY_ERROR(msg)                                            \
-    do {                                                             \
-        LOG1("VerifyError: %s", msg);                                \
-        exceptions_throw_verifyerror(STATE->m, msg);                 \
-        return false;                                                \
-    } while (0)
-
-#define IS_CAT1(slot)                                                \
-    ((slot).type != TYPE_VOID && !IS_2_WORD_TYPE((slot).type))
-
-#define IS_CAT2(slot)                                                \
-    ((slot).type != TYPE_VOID && IS_2_WORD_TYPE((slot).type))
-
-#define CHECK_CAT1(slot)                                             \
-    do {                                                             \
-        if (!IS_CAT1(slot))                                          \
-            goto throw_stack_category_error;                         \
-    } while (0)
-
-#define CHECK_CAT2(slot)                                             \
-    do {                                                             \
-        if (!IS_CAT2(slot))                                          \
-            goto throw_stack_category_error;                         \
-    } while (0)
-
-#define COPY_SLOT(s, d)                                              \
-    do { (d) = (s); } while (0)
-
-#define REACH_BLOCK(target)                                          \
-    do {                                                             \
-        if (!typecheck_stackbased_reach(STATE, (target), stack,      \
-                    (stack - stackfloor) + 1))                       \
-            return false;                                            \
-    } while (0)
-
-#define REACH(target)                                                \
-    do {                                                             \
-        REACH_BLOCK((target).block);                                 \
-    } while (0)
-
-#undef TYPECHECK_INT
-#undef TYPECHECK_LNG
-#undef TYPECHECK_FLT
-#undef TYPECHECK_DBL
-#undef TYPECHECK_ADR
-
-/* XXX should reuse typevector code */
-static typecheck_result typecheck_stackbased_merge_locals(methodinfo *m,
-                                                                                                                 typedescriptor_t *dst,
-                                                                                                                 typedescriptor_t *y,
-                                                                                                                 int size)
-{
-       bool changed = false;
-       typecheck_result r;
-
-       typedescriptor_t *a = dst;
-       typedescriptor_t *b = y;
-       while (size--) {
-               if (a->type != TYPE_VOID && a->type != b->type) {
-                       a->type = TYPE_VOID;
-                       changed = true;
-               }
-               else if (a->type == TYPE_ADR) {
-                       if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) {
-                               /* 'a' is a returnAddress */
-                               if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo)
-                                       || (TYPEINFO_RETURNADDRESS(a->typeinfo)
-                                               != TYPEINFO_RETURNADDRESS(b->typeinfo)))
-                               {
-                                       a->type = TYPE_VOID;
-                                       changed = true;
-                               }
-                       }
-                       else {
-                               /* 'a' is a reference */
-                               if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) {
-                                       a->type = TYPE_VOID;
-                                       changed = true;
-                               }
-                               else {
-                                       /* two reference types are merged. There cannot be */
-                                       /* a merge error. In the worst case we get j.l.O.  */
-                                       r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo));
-                                       if (r == typecheck_FAIL)
-                                               return r;
-                                       changed |= r;
-                               }
-                       }
-               }
-               a++;
-               b++;
-       }
-       return changed;
-}
-
-static typecheck_result typecheck_stackbased_merge(verifier_state *state,
-                                                                                                  basicblock *destblock,
-                                                                                                  typedescriptor_t *stack,
-                                                                                                  s4 stackdepth)
-{
-       s4 i;
-       s4 destidx;
-       typedescriptor_t *stackfloor;
-       typedescriptor_t *sp;
-       typedescriptor_t *dp;
-       typecheck_result r;
-       bool changed = false;
-
-       destidx = destblock->nr;
-
-       if (stackdepth != state->indepth[destidx]) {
-               exceptions_throw_verifyerror(state->m, "Stack depth mismatch");
-               return typecheck_FAIL;
-       }
-
-       stackfloor = stack - (stackdepth - 1);
-
-       sp = stackfloor;
-       dp = state->startstack + (destidx * state->m->maxstack);
-
-       for (i=0; i<stackdepth; ++i, ++sp, ++dp) {
-               if (sp->type != dp->type) {
-                       exceptions_throw_verifyerror(state->m, "Mismatched stack types");
-                       return typecheck_FAIL;
-               }
-               if (dp->type == TYPE_ADR) {
-                       if (TYPEINFO_IS_PRIMITIVE(dp->typeinfo)) {
-                               /* dp has returnAddress type */
-                               if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
-                                       if (TYPEINFO_RETURNADDRESS(dp->typeinfo) != TYPEINFO_RETURNADDRESS(sp->typeinfo)) {
-                                               exceptions_throw_verifyerror(state->m, "Mismatched stack types");
-                                               return typecheck_FAIL;
-                                       }
-                               }
-                               else {
-                                       exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
-                                       return typecheck_FAIL;
-                               }
-                       }
-                       else {
-                               /* dp has reference type */
-                               if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
-                                       exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
-                                       return typecheck_FAIL;
-                               }
-                               r = typeinfo_merge(state->m,&(dp->typeinfo),&(sp->typeinfo));
-                               if (r == typecheck_FAIL)
-                                       return r;
-                               changed |= r;
-                       }
-               }
-       }
-
-       dp = state->startlocals + (destidx * state->numlocals);
-       r = typecheck_stackbased_merge_locals(state->m, dp, state->locals, state->numlocals);
-       if (r == typecheck_FAIL)
-               return r;
-       changed |= r;
-
-       return changed;
-}
-
-static bool typecheck_stackbased_reach(verifier_state *state,
-                                                                          basicblock *destblock,
-                                                                          typedescriptor_t *stack,
-                                                                          s4 stackdepth)
-{
-       bool changed = false;
-       typecheck_result r;
-
-       assert(destblock);
-
-       if (destblock->flags == BBTYPECHECK_UNDEF) {
-               /* The destblock has never been reached before */
-
-               TYPECHECK_COUNT(stat_copied);
-               LOG1("block L%03d reached first time",destblock->nr); LOGSTR("\t");
-               DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
-
-               state->indepth[destblock->nr] = stackdepth;
-
-               MCOPY(state->startstack + (destblock->nr * state->m->maxstack),
-                         stack - (stackdepth - 1),
-                         typedescriptor_t,
-                         stackdepth);
-
-               MCOPY(state->startlocals + (destblock->nr * state->numlocals),
-                         state->locals,
-                         typedescriptor_t,
-                         state->numlocals);
-
-               changed = true;
-       }
-       else {
-               /* The destblock has already been reached before */
-
-               TYPECHECK_COUNT(stat_merged);
-               LOG1("block L%03d reached before", destblock->nr); LOGSTR("\t");
-               DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
-
-               r = typecheck_stackbased_merge(state, destblock, stack, stackdepth);
-               if (r == typecheck_FAIL)
-                       return false;
-               changed = r;
-
-               TYPECHECK_COUNTIF(changed,stat_merging_changed);
-       }
-
-       if (changed) {
-               LOG("\tchanged!");
-               destblock->flags = BBTYPECHECK_REACHED;
-               /* XXX is this check ok? */
-               if (destblock->nr <= state->bptr->nr) {
-                       LOG("\tREPEAT!");
-                       state->repeat = true;
-               }
-       }
-       return true;
-}
-
-
-/* typecheck_stackbased_verify_fieldaccess *************************************
-
-   Verify an ICMD_{GET,PUT}{STATIC,FIELD}
-
-   IN:
-       state............the current state of the verifier
-          instance.........the instance slot, or NULL
-          value............the value slot, or NULL
-          stack............stack after popping the arguments
-
-   RETURN VALUE:
-       stack pointer....successful verification,
-          NULL.............an exception has been thrown.
-
-*******************************************************************************/
-
-static typedescriptor_t *typecheck_stackbased_verify_fieldaccess(
-               verifier_state *state,
-               typedescriptor_t *instance,
-               typedescriptor_t *value,
-               typedescriptor_t *stack)
-{
-       jitdata *jd;
-
-       jd = state->jd;
-
-#define TYPECHECK_STACKBASED
-#define EXCEPTION  do { return NULL; } while (0)
-#define STATE  state
-#include <typecheck-fields.inc>
-#undef  EXCEPTION
-#undef  STATE
-#undef  TYPECHECK_STACKBASED
-
-       return stack;
-
-throw_stack_overflow:
-       LOG("STACK OVERFLOW!");
-       exceptions_throw_verifyerror(state->m, "Stack size too large");
-       return NULL;
-}
-
-static bool typecheck_stackbased_verify_invocation(verifier_state *state,
-                                                                                                  typedescriptor_t *stack,
-                                                                                                  typedescriptor_t *stackfloor)
-{
-       s4 paramslots;
-       methoddesc *md;
-       typedescriptor_t *dv;
-
-       /* check stack depth */
-
-       /* XXX parse params */
-
-       INSTRUCTION_GET_METHODDESC(state->iptr, md);
-
-       paramslots = md->paramslots;
-
-       if ((stack - stackfloor) + 1 < paramslots) {
-               exceptions_throw_verifyerror(state->m, 
-                               "Trying to pop operand of an empty stack");
-               return false;
-       }
-
-       dv = stack - (paramslots - 1);
-
-#define TYPECHECK_STACKBASED
-#define OP1   dv
-#include <typecheck-invoke.inc>
-#undef  OP1
-#undef  TYPECHECK_STACKBASED
-
-       return true;
-}
-
-static bool typecheck_stackbased_verify_builtin(verifier_state *state,
-                                                                                               typedescriptor_t *stack,
-                                                                                               typedescriptor_t *stackfloor)
-{
-       s4 paramslots;
-       typedescriptor_t *dv;
-
-       /* check stack depth */
-
-       /* XXX parse params */
-
-       paramslots = state->iptr->sx.s23.s3.bte->md->paramslots;
-
-       if ((stack - stackfloor) + 1 < paramslots) {
-               exceptions_throw_verifyerror(state->m, 
-                               "Trying to pop operand of an empty stack");
-               return false;
-       }
-
-       dv = stack - (paramslots - 1);
-
-#define TYPECHECK_STACKBASED
-#define OP1   dv
-#define TYPECHECK_INT(s)  CHECK_STACK_TYPE(*(s), TYPE_INT)
-#define TYPECHECK_ADR(s)  CHECK_STACK_TYPE(*(s), TYPE_ADR)
-#define TYPECHECK_LNG(s)  CHECK_STACK_TYPE(*(s), TYPE_LNG)
-#define TYPECHECK_FLT(s)  CHECK_STACK_TYPE(*(s), TYPE_FLT)
-#define TYPECHECK_DBL(s)  CHECK_STACK_TYPE(*(s), TYPE_DBL)
-#include <typecheck-builtins.inc>
-#undef  OP1
-#undef  TYPECHECK_STACKBASED
-
-       return true;
-
-throw_stack_type_error:
-       exceptions_throw_verifyerror(state->m, "Wrong type on stack"); /* XXX */
-       return false;
-}
-
-static bool typecheck_stackbased_multianewarray(verifier_state *state,
-                                                                                               typedescriptor_t *stack,
-                                                                                               typedescriptor_t *stackfloor)
-{
-       /* XXX recombine with verify_multianewarray */
-
-       classinfo *arrayclass;
-       arraydescriptor *desc;
-       s4 i;
-       typedescriptor_t *sp;
-       typedescriptor_t *dst;
-
-       /* destination slot */
-
-       i = state->iptr->s1.argcount;
-
-       dst = stack - (i-1);
-
-       /* check the array lengths on the stack */
-
-       if ((stack - stackfloor) + 1 < i) {
-               exceptions_throw_verifyerror(state->m, 
-                               "Trying to pop operand of an empty stack");
-               return false;
-       }
-
-       if (i < 1)
-               TYPECHECK_VERIFYERROR_bool("Illegal dimension argument");
-
-       for (sp = dst; sp <= stack; ++sp) {
-               if (sp->type != TYPE_INT) {
-                       exceptions_throw_verifyerror_for_stack(state->m, TYPE_INT);
-                       return false;
-               }
-       }
-
-       /* check array descriptor */
-
-       if (INSTRUCTION_IS_RESOLVED(state->iptr)) {
-               /* the array class reference has already been resolved */
-               arrayclass = state->iptr->sx.s23.s3.c.cls;
-               if (!arrayclass)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with unlinked class");
-               if ((desc = arrayclass->vftbl->arraydesc) == NULL)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
-               if (desc->dimension < state->iptr->s1.argcount)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
-
-               /* set the array type of the result */
-               typeinfo_init_classinfo(&(dst->typeinfo), arrayclass);
-       }
-       else {
-               const char *p;
-               constant_classref *cr;
-
-               /* the array class reference is still unresolved */
-               /* check that the reference indicates an array class of correct dimension */
-               cr = state->iptr->sx.s23.s3.c.ref;
-               i = 0;
-               p = cr->name->text;
-               while (p[i] == '[')
-                       i++;
-               /* { the dimension of the array class == i } */
-               if (i < 1)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
-               if (i < state->iptr->s1.argcount)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
-
-               /* set the array type of the result */
-               if (!typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(cr)))
-                       return false;
-       }
-
-       /* everything ok */
-       return true;
-
-}
-
-static void typecheck_stackbased_add_jsr_caller(typecheck_jsr_t *jsr,
-                                                                                               basicblock *bptr)
-{
-       typecheck_jsr_caller_t *jc;
-
-       for (jc = jsr->callers; jc; jc = jc->next)
-               if (jc->callblock == bptr)
-                       return;
-
-       jc = DNEW(typecheck_jsr_caller_t);
-       jc->next = jsr->callers;
-       jc->callblock = bptr;
-       jsr->callers = jc;
-}
-
-static typedescriptor_t *typecheck_stackbased_jsr(verifier_state *state,
-                                                                                               typedescriptor_t *stack,
-                                                                                               typedescriptor_t *stackfloor)
-{
-       typecheck_jsr_t *jsr;
-       basicblock *tbptr;
-       jitdata *jd;
-       s4 i;
-
-       jd = state->jd;
-
-       tbptr = state->iptr->sx.s23.s3.jsrtarget.block;
-       jsr = state->jsrinfos[tbptr->nr];
-
-       if (jsr && tbptr->flags == BBFINISHED) {
-
-               LOG1("another JSR to analysed subroutine L%03d", tbptr->nr);
-               if (jsr->active) {
-                       exceptions_throw_verifyerror(state->m, "Recursive JSR");
-                       return NULL;
-               }
-
-               assert(jsr->callers);
-               assert(jsr->callers->callblock);
-
-               /* copy the stack of the RET edge */
-
-               MCOPY(stackfloor, jsr->retstack, typedescriptor_t, jsr->retdepth);
-               stack = stackfloor + (jsr->retdepth - 1);
-
-               /* copy variables that were used in the subroutine from the RET edge */
-
-               for (i=0; i<state->numlocals; ++i)
-                       if (jsr->usedlocals[i])
-                               state->locals[i] = jsr->retlocals[i];
-
-               /* reach the following block */
-
-               if (!typecheck_stackbased_reach(state, state->bptr->next, stack, 
-                                       (stack - stackfloor) + 1))
-                       return NULL;
-       }
-       else {
-               if (!jsr) {
-                       LOG1("first JSR to block L%03d", tbptr->nr);
-
-                       jsr = DNEW(typecheck_jsr_t);
-                       state->jsrinfos[tbptr->nr] = jsr;
-                       jsr->callers = NULL;
-                       jsr->blockflags = DMNEW(char, state->basicblockcount);
-                       jsr->retblock = NULL;
-                       jsr->start = tbptr;
-                       jsr->usedlocals = DMNEW(char, state->numlocals);
-                       MZERO(jsr->usedlocals, char, state->numlocals);
-                       jsr->retlocals = DMNEW(typedescriptor_t, state->numlocals);
-                       jsr->retstack = DMNEW(typedescriptor_t, state->m->maxstack);
-                       jsr->retdepth = 0;
-               }
-               else {
-                       LOG1("re-analysing JSR to block L%03d", tbptr->nr);
-               }
-
-               jsr->active = true;
-               jsr->next = state->topjsr;
-               state->topjsr = jsr;
-
-               assert(state->iptr->sx.s23.s3.jsrtarget.block->flags == BBTYPECHECK_REACHED);
-
-               tbptr->flags = BBFINISHED;
-
-               for (tbptr = state->basicblocks; tbptr != NULL; tbptr = tbptr->next) {
-                       jsr->blockflags[tbptr->nr] = tbptr->flags;
-
-                       if (tbptr->flags == BBTYPECHECK_REACHED)
-                               tbptr->flags = BBFINISHED;
-               }
-
-               state->iptr->sx.s23.s3.jsrtarget.block->flags = BBTYPECHECK_REACHED;
-       }
-
-       /* register this block as a caller, if not already done */
-
-       typecheck_stackbased_add_jsr_caller(jsr, state->bptr);
-
-       return stack;
-}
-
-static bool typecheck_stackbased_ret(verifier_state *state,
-                                                                        typedescriptor_t *stack,
-                                                                        typedescriptor_t *stackfloor)
-{
-       basicblock *tbptr;
-       typecheck_jsr_caller_t *jsrcaller;
-       typecheck_jsr_t *jsr;
-       s4 i;
-
-       /* get the subroutine we are RETurning from */
-
-       tbptr = TYPEINFO_RETURNADDRESS(state->locals[state->iptr->s1.varindex].typeinfo);
-       if (tbptr == NULL) {
-               exceptions_throw_verifyerror(state->m, "Illegal RET");
-               return false;
-       }
-
-       LOG1("RET from subroutine L%03d", tbptr->nr);
-       jsr = state->jsrinfos[tbptr->nr];
-       assert(jsr);
-
-       /* check against recursion */
-
-       if (!jsr->active) {
-               exceptions_throw_verifyerror(state->m, "RET outside of local subroutine");
-               return false;
-       }
-
-       /* check against multiple RETs for one subroutine */
-
-       if (jsr->retblock && jsr->retblock != state->bptr) {
-               exceptions_throw_verifyerror(state->m, "Multiple RETs from local subroutine");
-               return false;
-       }
-
-       /* store data-flow of the RET edge */
-
-       jsr->retblock = state->bptr;
-       jsr->retdepth = (stack - stackfloor) + 1;
-       MCOPY(jsr->retstack, stackfloor, typedescriptor_t, jsr->retdepth);
-       MCOPY(jsr->retlocals, state->locals, typedescriptor_t, state->numlocals);
-
-       /* invalidate the returnAddress used by this RET */
-       /* XXX should we also invalidate the returnAddresses of JSRs that are skipped by this RET? */
-
-       for (i=0; i<state->numlocals; ++i) {
-               typedescriptor_t *lc = &(jsr->retlocals[i]);
-               if (TYPE_IS_RETURNADDRESS(lc->type, lc->typeinfo))
-                       if (TYPEINFO_RETURNADDRESS(lc->typeinfo) == tbptr) {
-                               LOG1("invalidating returnAddress in local %d", i);
-                               TYPEINFO_INIT_RETURNADDRESS(lc->typeinfo, NULL);
-                       }
-       }
-
-       /* touch all callers of the subroutine, so they are analysed again */
-
-       for (jsrcaller = jsr->callers; jsrcaller != NULL; jsrcaller = jsrcaller->next) {
-               tbptr = jsrcaller->callblock;
-               LOG1("touching caller L%03d from RET", tbptr->nr);
-               assert(jsr->blockflags[tbptr->nr] >= BBFINISHED);
-               jsr->blockflags[tbptr->nr] = BBTYPECHECK_REACHED; /* XXX repeat? */
-       }
-
-       return true;
-}
-
-bool typecheck_stackbased(jitdata *jd)
-{
-       register verifier_slot_t *stack;
-       verifier_slot_t *stackfloor;
-       s4 len;
-       methoddesc *md;
-       bool maythrow;
-       bool superblockend;
-       verifier_slot_t temp;
-       branch_target_t *table;
-       lookup_target_t *lookup;
-       s4 i;
-       typecheck_result r;
-       verifier_slot_t *dst;
-       verifier_state state;
-       basicblock *tbptr;
-       exception_entry *ex;
-       typedescriptor_t exstack;
-       s4 skip = 0;
-
-       DOLOG( show_method(jd, SHOW_PARSE); );
-
-       /* initialize verifier state */
-
-       state.jd = jd;
-       state.m = jd->m;
-       state.cd = jd->cd;
-       state.basicblocks = jd->basicblocks;
-       state.basicblockcount = jd->basicblockcount;
-       state.topjsr = NULL;
-#   define STATE (&state)
-
-       /* check that the basicblock numbers are valid */
-
-#if !defined(NDEBUG)
-       jit_check_basicblock_numbers(jd);
-#endif
-
-       /* check if this method is an instance initializer method */
-
-    state.initmethod = (state.m->name == utf_init);
-
-       /* allocate parameter descriptors if necessary */
-
-       if (!state.m->parseddesc->params)
-               if (!descriptor_params_from_paramtypes(state.m->parseddesc,state.m->flags))
-                       return false;
-
-       /* allocate the stack buffers */
-
-       stackfloor = DMNEW(verifier_slot_t, state.m->maxstack + 1);
-       state.stackceiling = stackfloor + state.m->maxstack;
-       stack = stackfloor - 1;
-       state.indepth = DMNEW(s4, state.basicblockcount);
-       state.startstack = DMNEW(verifier_slot_t, state.m->maxstack * state.basicblockcount);
-
-       /* allocate the local variables buffers */
-
-       state.numlocals = state.m->maxlocals;
-       state.validlocals = state.m->maxlocals;
-    if (state.initmethod)
-               state.numlocals++; /* extra marker variable */
-
-       state.locals = DMNEW(verifier_slot_t, state.numlocals);
-       state.startlocals = DMNEW(verifier_slot_t, state.numlocals * state.basicblockcount);
-
-    /* allocate the buffer of active exception handlers */
-
-    state.handlers = DMNEW(exception_entry*, state.jd->exceptiontablelength + 1);
-
-    /* initialize instack of exception handlers */
-
-       exstack.type = TYPE_ADR;
-       typeinfo_init_classinfo(&(exstack.typeinfo),
-                                                       class_java_lang_Throwable); /* changed later */
-
-    LOG("Exception handler stacks set.\n");
-
-       /* initialize jsr info buffer */
-
-       state.jsrinfos = DMNEW(typecheck_jsr_t *, state.basicblockcount);
-       MZERO(state.jsrinfos, typecheck_jsr_t *, state.basicblockcount);
-
-       /* initialize stack of first block */
-
-       state.indepth[0] = 0;
-
-       /* initialize locals of first block */
-
-    /* if this is an instance method initialize the "this" ref type */
-
-    if (!(state.m->flags & ACC_STATIC)) {
-               if (state.validlocals < 1)
-                       VERIFY_ERROR("Not enough local variables for method arguments");
-               dst = state.startlocals;
-               dst->type = TYPE_ADR;
-               if (state.initmethod)
-                       TYPEINFO_INIT_NEWOBJECT(dst->typeinfo, NULL);
-               else
-                       typeinfo_init_classinfo(&(dst->typeinfo), state.m->clazz);
-
-               skip = 1;
-    }
-
-    LOG("'this' argument set.\n");
-
-       len = typedescriptors_init_from_methoddesc(state.startlocals + skip,
-                       state.m->parseddesc,
-                       state.validlocals, true, skip, &state.returntype);
-       if (len < 0)
-               return false;
-
-       /* set remaining locals to void */
-
-       for (i = skip + len; i<state.numlocals; ++i)
-               state.startlocals[i].type = TYPE_VOID;
-
-       /* initialize block flags */
-
-       typecheck_init_flags(&state, BBUNDEF);
-
-       /* iterate until fixpoint reached */
-
-       do {
-
-               state.repeat = false;
-
-               /* iterate over the basic blocks */
-
-               for (state.bptr = state.basicblocks; state.bptr != NULL; state.bptr = state.bptr->next) {
-
-                       if (state.bptr->flags != BBTYPECHECK_REACHED)
-                               continue;
-
-                       DOLOG( show_basicblock(jd, state.bptr, SHOW_PARSE); );
-
-                       /* mark this block as analysed */
-
-                       state.bptr->flags = BBFINISHED;
-
-                       /* determine the active exception handlers for this block */
-                       /* XXX could use a faster algorithm with sorted lists or  */
-                       /* something?                                             */
-                       /* XXX reuse code from variables based verifer? */
-                       len = 0;
-                       for (ex = STATE->jd->exceptiontable; ex ; ex = ex->down) {
-                               if ((ex->start->nr <= STATE->bptr->nr) && (ex->end->nr > STATE->bptr->nr)) {
-                                       LOG1("\tactive handler L%03d", ex->handler->nr);
-                                       STATE->handlers[len++] = ex;
-                               }
-                       }
-                       STATE->handlers[len] = NULL;
-
-                       /* initialize the locals */
-
-                       MCOPY(state.locals,
-                                 state.startlocals + (state.bptr->nr * state.numlocals),
-                                 verifier_slot_t, state.numlocals);
-
-                       /* initialize the stack */
-
-                       len = state.indepth[state.bptr->nr];
-
-                       MCOPY(stackfloor,
-                                 state.startstack + (state.bptr->nr * state.m->maxstack),
-                                 verifier_slot_t, len);
-
-                       stack = stackfloor + (len - 1);
-
-                       /* iterate over the instructions in this block */
-
-                       state.iptr = state.bptr->iinstr;
-                       len = state.bptr->icount;
-
-                       superblockend = false;
-
-                       for (; len--; state.iptr++) {
-
-                               maythrow = false;
-
-                               LOGNL;
-                               DOLOG( typecheck_stackbased_show_state(&state, stack, stackfloor, true); );
-
-                               switch (state.iptr->opc) {
-#define TYPECHECK_STACKBASED 1
-#define STATE (&state)
-#define IPTR state.iptr
-#define BPTR state.bptr
-#define METHOD state.m
-#define LOCAL_SLOT(index)  (state.locals + (index))
-#define EXCEPTION                                                    \
-    do {                                                             \
-        LOG("EXCEPTION THROWN!\n");                                  \
-        return false;                                                \
-    } while (0)
-
-#include <typecheck-stackbased-gen.inc>
-#undef  TYPECHECK_STACKBASED
-                               }
-
-                               /* reach exception handlers for this instruction */
-
-                               if (maythrow) {
-                                       TYPECHECK_COUNT(stat_ins_maythrow);
-                                       TYPECHECK_MARK(STATE->stat_maythrow);
-                                       LOG("\treaching exception handlers");
-                                       i = 0;
-                                       while (STATE->handlers[i]) {
-                                               TYPECHECK_COUNT(stat_handlers_reached);
-                                               if (STATE->handlers[i]->catchtype.any)
-                                                       exstack.typeinfo.typeclass = STATE->handlers[i]->catchtype;
-                                               else
-                                                       exstack.typeinfo.typeclass.cls = class_java_lang_Throwable;
-                                               if (!typecheck_stackbased_reach(
-                                                               STATE,
-                                                               STATE->handlers[i]->handler,
-                                                               &exstack, 1))
-                                                       EXCEPTION;
-                                               i++;
-                                       }
-                               }
-                       }
-
-                       /* propagate types to the following block */
-
-                       if (!superblockend) {
-                               if (!typecheck_stackbased_reach(&state, state.bptr->next,
-                                                                                               stack, stack - stackfloor + 1))
-                                       EXCEPTION;
-                       }
-               } /* end loop over blocks */
-
-               while (!state.repeat && state.topjsr) {
-                       LOG1("done analysing subroutine L%03d", state.topjsr->start->nr);
-
-                       /* propagate down used locals */
-
-                       if (state.topjsr->next) {
-                               for (i=0; i<state.numlocals; ++i)
-                                       state.topjsr->next->usedlocals[i] |= state.topjsr->usedlocals[i];
-                       }
-
-                       /* restore REACHED flags */
-
-                       for (tbptr = state.basicblocks; tbptr != NULL; tbptr = tbptr->next) {
-                               assert(tbptr->flags != BBTYPECHECK_REACHED);
-                               if (state.topjsr->blockflags[tbptr->nr] == BBTYPECHECK_REACHED) {
-                                       tbptr->flags = BBTYPECHECK_REACHED;
-                                       state.repeat = true;
-                               }
-                       }
-
-                       /* dactivate the subroutine */
-
-                       state.topjsr->active = false;
-                       state.topjsr = state.topjsr->next;
-               }
-       } while (state.repeat);
-
-       /* reset block flags */
-
-       typecheck_reset_flags(&state);
-
-       LOG("typecheck_stackbased successful");
-
-       return true;
-
-throw_stack_underflow:
-       LOG("STACK UNDERFLOW!");
-       exceptions_throw_verifyerror(state.m, "Unable to pop operand off an empty stack");
-       return false;
-
-throw_stack_overflow:
-       LOG("STACK OVERFLOW!");
-       exceptions_throw_verifyerror(state.m, "Stack size too large");
-       return false;
-
-throw_stack_type_error:
-       LOG("STACK TYPE ERROR!");
-       exceptions_throw_verifyerror(state.m, "Mismatched stack types");
-       return false;
-
-throw_local_type_error:
-       LOG("LOCAL TYPE ERROR!");
-       exceptions_throw_verifyerror(state.m, "Local variable type mismatch");
-       return false;
-
-throw_stack_category_error:
-       LOG("STACK CATEGORY ERROR!");
-       exceptions_throw_verifyerror(state.m, "Attempt to split long or double on the stack");
-       return false;
-}
-
-
-#if defined(TYPECHECK_VERBOSE)
-static void typecheck_stackbased_show_state(verifier_state *state,
-                                                                                       typedescriptor_t *stack,
-                                                                                       typedescriptor_t *stackfloor,
-                                                                                       bool showins)
-{
-       typedescriptor_t *sp;
-       s4 i;
-
-       LOGSTR1("stackdepth %d stack [", (stack - stackfloor) + 1);
-       for (sp=stackfloor; sp <= stack; sp++) {
-               LOGSTR(" ");
-               DOLOG( typedescriptor_print(stdout, sp); );
-       }
-       LOGSTR(" ] locals [");
-       for (i=0; i<state->numlocals; ++i) {
-               LOGSTR(" ");
-               DOLOG( typedescriptor_print(stdout, state->locals + i); );
-       }
-       LOGSTR(" ]");
-       LOGNL;
-       if (showins && state->iptr < (state->bptr->iinstr + state->bptr->icount)) {
-               LOGSTR("\t");
-               DOLOG( show_icmd(state->jd, state->iptr, false, SHOW_PARSE); );
-               LOGNL;
-       }
-}
-#endif
-
-#endif /* defined(ENABLE_VERIFIER) */
-
-
-/*
- * 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/jit/verify/typecheck-stackbased.cpp b/src/vm/jit/verify/typecheck-stackbased.cpp
new file mode 100644 (file)
index 0000000..8ac6267
--- /dev/null
@@ -0,0 +1,1034 @@
+/* src/vm/jit/verify/typecheck-stackbased.c - stack-based verifier
+
+   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 "vm/jit/builtin.hpp"
+#include "mm/memory.h"
+
+#include "vm/array.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/globals.hpp"
+#include "vm/primitive.hpp"
+
+#include "vm/jit/parse.hpp"
+#include "vm/jit/show.hpp"
+#include "vm/jit/stack.h"
+#include "vm/jit/verify/typecheck-common.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* this #if runs over the whole file: */
+#if defined(ENABLE_VERIFIER)
+
+typedef typedescriptor_t verifier_slot_t;
+
+#if defined(TYPECHECK_VERBOSE)
+static void typecheck_stackbased_show_state(verifier_state *state,
+                                                                                       typedescriptor *stack,
+                                                                                       typedescriptor *stackfloor,
+                                                                                       bool showins);
+#endif
+
+
+#define CHECK_STACK_DEPTH(d)                                         \
+    if (((u1*)stack - (u1*)stackfloor)                               \
+            < (((d)-1) * (int)sizeof(verifier_slot_t)))              \
+        goto throw_stack_underflow;
+
+/* XXX don't need to check against ACONST for every ICMD */
+#define CHECK_STACK_SPACE(d)                                         \
+    if (((u1*)STATE->stackceiling - (u1*)stack)                      \
+            < (((d)+1) * (int)sizeof(verifier_slot_t)))              \
+        if (STATE->iptr->opc != ICMD_ACONST                          \
+                || INSTRUCTION_MUST_CHECK(STATE->iptr))              \
+            goto throw_stack_overflow;
+
+#define CHECK_STACK_TYPE(s, t)                                       \
+    if ((s).type != (t))                                             \
+        goto throw_stack_type_error;
+
+/* XXX inefficient */
+#define CHECK_LOCAL_TYPE(index, t)                                   \
+    do {                                                             \
+        if (state.locals[(index)].type != (t))                       \
+            goto throw_local_type_error;                             \
+        if (STATE->topjsr)                                           \
+            STATE->topjsr->usedlocals[(index)] = 1;                  \
+        if (STATE->topjsr && IS_2_WORD_TYPE(t))                      \
+            STATE->topjsr->usedlocals[(index) + 1] = 1;              \
+    } while(0)
+
+/* XXX inefficient */
+#define STORE_LOCAL(t, index)                                        \
+    do {                                                             \
+        state.locals[(index)].type = (t);                            \
+        if ((index) && IS_2_WORD_TYPE(state.locals[(index)-1].type)) \
+            state.locals[(index-1)].type = TYPE_VOID;                \
+        if (STATE->topjsr)                                           \
+            STATE->topjsr->usedlocals[(index)] = 1;                  \
+    } while (0)
+
+/* XXX inefficient */
+#define STORE_LOCAL_2_WORD(t, index)                                 \
+    do {                                                             \
+        STORE_LOCAL(t, index);                                       \
+        state.locals[(index)+1].type = TYPE_VOID;                    \
+        if (STATE->topjsr)                                           \
+            STATE->topjsr->usedlocals[(index)] = 1;                  \
+    } while (0)
+
+#define VERIFY_ERROR(msg)                                            \
+    do {                                                             \
+        LOG1("VerifyError: %s", msg);                                \
+        exceptions_throw_verifyerror(STATE->m, msg);                 \
+        return false;                                                \
+    } while (0)
+
+#define IS_CAT1(slot)                                                \
+    ((slot).type != TYPE_VOID && !IS_2_WORD_TYPE((slot).type))
+
+#define IS_CAT2(slot)                                                \
+    ((slot).type != TYPE_VOID && IS_2_WORD_TYPE((slot).type))
+
+#define CHECK_CAT1(slot)                                             \
+    do {                                                             \
+        if (!IS_CAT1(slot))                                          \
+            goto throw_stack_category_error;                         \
+    } while (0)
+
+#define CHECK_CAT2(slot)                                             \
+    do {                                                             \
+        if (!IS_CAT2(slot))                                          \
+            goto throw_stack_category_error;                         \
+    } while (0)
+
+#define COPY_SLOT(s, d)                                              \
+    do { (d) = (s); } while (0)
+
+#define REACH_BLOCK(target)                                          \
+    do {                                                             \
+        if (!typecheck_stackbased_reach(STATE, (target), stack,      \
+                    (stack - stackfloor) + 1))                       \
+            return false;                                            \
+    } while (0)
+
+#define REACH(target)                                                \
+    do {                                                             \
+        REACH_BLOCK((target).block);                                 \
+    } while (0)
+
+#undef TYPECHECK_INT
+#undef TYPECHECK_LNG
+#undef TYPECHECK_FLT
+#undef TYPECHECK_DBL
+#undef TYPECHECK_ADR
+
+/* XXX should reuse typevector code */
+static typecheck_result typecheck_stackbased_merge_locals(methodinfo *m,
+                                                                                                                 typedescriptor_t *dst,
+                                                                                                                 typedescriptor_t *y,
+                                                                                                                 int size)
+{
+       bool changed = false;
+       typecheck_result r;
+
+       typedescriptor_t *a = dst;
+       typedescriptor_t *b = y;
+       while (size--) {
+               if (a->type != TYPE_VOID && a->type != b->type) {
+                       a->type = TYPE_VOID;
+                       changed = true;
+               }
+               else if (a->type == TYPE_ADR) {
+                       if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) {
+                               /* 'a' is a returnAddress */
+                               if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo)
+                                       || (TYPEINFO_RETURNADDRESS(a->typeinfo)
+                                               != TYPEINFO_RETURNADDRESS(b->typeinfo)))
+                               {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                       }
+                       else {
+                               /* 'a' is a reference */
+                               if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                               else {
+                                       /* two reference types are merged. There cannot be */
+                                       /* a merge error. In the worst case we get j.l.O.  */
+                                       r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo));
+                                       if (r == typecheck_FAIL)
+                                               return r;
+                                       changed |= r;
+                               }
+                       }
+               }
+               a++;
+               b++;
+       }
+       return (typecheck_result) changed;
+}
+
+static typecheck_result typecheck_stackbased_merge(verifier_state *state,
+                                                                                                  basicblock *destblock,
+                                                                                                  typedescriptor_t *stack,
+                                                                                                  s4 stackdepth)
+{
+       s4 i;
+       s4 destidx;
+       typedescriptor_t *stackfloor;
+       typedescriptor_t *sp;
+       typedescriptor_t *dp;
+       typecheck_result r;
+       bool changed = false;
+
+       destidx = destblock->nr;
+
+       if (stackdepth != state->indepth[destidx]) {
+               exceptions_throw_verifyerror(state->m, "Stack depth mismatch");
+               return typecheck_FAIL;
+       }
+
+       stackfloor = stack - (stackdepth - 1);
+
+       sp = stackfloor;
+       dp = state->startstack + (destidx * state->m->maxstack);
+
+       for (i=0; i<stackdepth; ++i, ++sp, ++dp) {
+               if (sp->type != dp->type) {
+                       exceptions_throw_verifyerror(state->m, "Mismatched stack types");
+                       return typecheck_FAIL;
+               }
+               if (dp->type == TYPE_ADR) {
+                       if (TYPEINFO_IS_PRIMITIVE(dp->typeinfo)) {
+                               /* dp has returnAddress type */
+                               if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
+                                       if (TYPEINFO_RETURNADDRESS(dp->typeinfo) != TYPEINFO_RETURNADDRESS(sp->typeinfo)) {
+                                               exceptions_throw_verifyerror(state->m, "Mismatched stack types");
+                                               return typecheck_FAIL;
+                                       }
+                               }
+                               else {
+                                       exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
+                                       return typecheck_FAIL;
+                               }
+                       }
+                       else {
+                               /* dp has reference type */
+                               if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
+                                       exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
+                                       return typecheck_FAIL;
+                               }
+                               r = typeinfo_merge(state->m,&(dp->typeinfo),&(sp->typeinfo));
+                               if (r == typecheck_FAIL)
+                                       return r;
+                               changed |= r;
+                       }
+               }
+       }
+
+       dp = state->startlocals + (destidx * state->numlocals);
+       r = typecheck_stackbased_merge_locals(state->m, dp, state->locals, state->numlocals);
+       if (r == typecheck_FAIL)
+               return r;
+       changed |= r;
+
+       return (typecheck_result) changed;
+}
+
+static bool typecheck_stackbased_reach(verifier_state *state,
+                                                                          basicblock *destblock,
+                                                                          typedescriptor_t *stack,
+                                                                          s4 stackdepth)
+{
+       bool changed = false;
+       typecheck_result r;
+
+       assert(destblock);
+
+       if (destblock->flags == BBTYPECHECK_UNDEF) {
+               /* The destblock has never been reached before */
+
+               TYPECHECK_COUNT(stat_copied);
+               LOG1("block L%03d reached first time",destblock->nr); LOGSTR("\t");
+               DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
+
+               state->indepth[destblock->nr] = stackdepth;
+
+               MCOPY(state->startstack + (destblock->nr * state->m->maxstack),
+                         stack - (stackdepth - 1),
+                         typedescriptor_t,
+                         stackdepth);
+
+               MCOPY(state->startlocals + (destblock->nr * state->numlocals),
+                         state->locals,
+                         typedescriptor_t,
+                         state->numlocals);
+
+               changed = true;
+       }
+       else {
+               /* The destblock has already been reached before */
+
+               TYPECHECK_COUNT(stat_merged);
+               LOG1("block L%03d reached before", destblock->nr); LOGSTR("\t");
+               DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
+
+               r = typecheck_stackbased_merge(state, destblock, stack, stackdepth);
+               if (r == typecheck_FAIL)
+                       return false;
+               changed = r;
+
+               TYPECHECK_COUNTIF(changed,stat_merging_changed);
+       }
+
+       if (changed) {
+               LOG("\tchanged!");
+               destblock->flags = BBTYPECHECK_REACHED;
+               /* XXX is this check ok? */
+               if (destblock->nr <= state->bptr->nr) {
+                       LOG("\tREPEAT!");
+                       state->repeat = true;
+               }
+       }
+       return true;
+}
+
+
+/* typecheck_stackbased_verify_fieldaccess *************************************
+
+   Verify an ICMD_{GET,PUT}{STATIC,FIELD}
+
+   IN:
+       state............the current state of the verifier
+          instance.........the instance slot, or NULL
+          value............the value slot, or NULL
+          stack............stack after popping the arguments
+
+   RETURN VALUE:
+       stack pointer....successful verification,
+          NULL.............an exception has been thrown.
+
+*******************************************************************************/
+
+static typedescriptor_t *typecheck_stackbased_verify_fieldaccess(
+               verifier_state *state,
+               typedescriptor_t *instance,
+               typedescriptor_t *value,
+               typedescriptor_t *stack)
+{
+       jitdata *jd;
+
+       jd = state->jd;
+
+#define TYPECHECK_STACKBASED
+#define EXCEPTION  do { return NULL; } while (0)
+#define STATE  state
+#include <typecheck-fields.inc>
+#undef  EXCEPTION
+#undef  STATE
+#undef  TYPECHECK_STACKBASED
+
+       return stack;
+
+throw_stack_overflow:
+       LOG("STACK OVERFLOW!");
+       exceptions_throw_verifyerror(state->m, "Stack size too large");
+       return NULL;
+}
+
+static bool typecheck_stackbased_verify_invocation(verifier_state *state,
+                                                                                                  typedescriptor_t *stack,
+                                                                                                  typedescriptor_t *stackfloor)
+{
+       s4 paramslots;
+       methoddesc *md;
+       typedescriptor_t *dv;
+
+       /* check stack depth */
+
+       /* XXX parse params */
+
+       INSTRUCTION_GET_METHODDESC(state->iptr, md);
+
+       paramslots = md->paramslots;
+
+       if ((stack - stackfloor) + 1 < paramslots) {
+               exceptions_throw_verifyerror(state->m, 
+                               "Trying to pop operand of an empty stack");
+               return false;
+       }
+
+       dv = stack - (paramslots - 1);
+
+#define TYPECHECK_STACKBASED
+#define OP1   dv
+#include <typecheck-invoke.inc>
+#undef  OP1
+#undef  TYPECHECK_STACKBASED
+
+       return true;
+}
+
+static bool typecheck_stackbased_verify_builtin(verifier_state *state,
+                                                                                               typedescriptor_t *stack,
+                                                                                               typedescriptor_t *stackfloor)
+{
+       s4 paramslots;
+       typedescriptor_t *dv;
+
+       /* check stack depth */
+
+       /* XXX parse params */
+
+       paramslots = state->iptr->sx.s23.s3.bte->md->paramslots;
+
+       if ((stack - stackfloor) + 1 < paramslots) {
+               exceptions_throw_verifyerror(state->m, 
+                               "Trying to pop operand of an empty stack");
+               return false;
+       }
+
+       dv = stack - (paramslots - 1);
+
+#define TYPECHECK_STACKBASED
+#define OP1   dv
+#define TYPECHECK_INT(s)  CHECK_STACK_TYPE(*(s), TYPE_INT)
+#define TYPECHECK_ADR(s)  CHECK_STACK_TYPE(*(s), TYPE_ADR)
+#define TYPECHECK_LNG(s)  CHECK_STACK_TYPE(*(s), TYPE_LNG)
+#define TYPECHECK_FLT(s)  CHECK_STACK_TYPE(*(s), TYPE_FLT)
+#define TYPECHECK_DBL(s)  CHECK_STACK_TYPE(*(s), TYPE_DBL)
+#include <typecheck-builtins.inc>
+#undef  OP1
+#undef  TYPECHECK_STACKBASED
+
+       return true;
+
+throw_stack_type_error:
+       exceptions_throw_verifyerror(state->m, "Wrong type on stack"); /* XXX */
+       return false;
+}
+
+static bool typecheck_stackbased_multianewarray(verifier_state *state,
+                                                                                               typedescriptor_t *stack,
+                                                                                               typedescriptor_t *stackfloor)
+{
+       /* XXX recombine with verify_multianewarray */
+
+       classinfo *arrayclass;
+       arraydescriptor *desc;
+       s4 i;
+       typedescriptor_t *sp;
+       typedescriptor_t *dst;
+
+       /* destination slot */
+
+       i = state->iptr->s1.argcount;
+
+       dst = stack - (i-1);
+
+       /* check the array lengths on the stack */
+
+       if ((stack - stackfloor) + 1 < i) {
+               exceptions_throw_verifyerror(state->m, 
+                               "Trying to pop operand of an empty stack");
+               return false;
+       }
+
+       if (i < 1)
+               TYPECHECK_VERIFYERROR_bool("Illegal dimension argument");
+
+       for (sp = dst; sp <= stack; ++sp) {
+               if (sp->type != TYPE_INT) {
+                       exceptions_throw_verifyerror_for_stack(state->m, TYPE_INT);
+                       return false;
+               }
+       }
+
+       /* check array descriptor */
+
+       if (INSTRUCTION_IS_RESOLVED(state->iptr)) {
+               /* the array class reference has already been resolved */
+               arrayclass = state->iptr->sx.s23.s3.c.cls;
+               if (!arrayclass)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with unlinked class");
+               if ((desc = arrayclass->vftbl->arraydesc) == NULL)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
+               if (desc->dimension < state->iptr->s1.argcount)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
+
+               /* set the array type of the result */
+               typeinfo_init_classinfo(&(dst->typeinfo), arrayclass);
+       }
+       else {
+               const char *p;
+               constant_classref *cr;
+
+               /* the array class reference is still unresolved */
+               /* check that the reference indicates an array class of correct dimension */
+               cr = state->iptr->sx.s23.s3.c.ref;
+               i = 0;
+               p = cr->name->text;
+               while (p[i] == '[')
+                       i++;
+               /* { the dimension of the array class == i } */
+               if (i < 1)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
+               if (i < state->iptr->s1.argcount)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
+
+               /* set the array type of the result */
+               if (!typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(cr)))
+                       return false;
+       }
+
+       /* everything ok */
+       return true;
+
+}
+
+static void typecheck_stackbased_add_jsr_caller(typecheck_jsr_t *jsr,
+                                                                                               basicblock *bptr)
+{
+       typecheck_jsr_caller_t *jc;
+
+       for (jc = jsr->callers; jc; jc = jc->next)
+               if (jc->callblock == bptr)
+                       return;
+
+       jc = (typecheck_jsr_caller_t*) DumpMemory::allocate(sizeof(typecheck_jsr_caller_t));
+       jc->next = jsr->callers;
+       jc->callblock = bptr;
+       jsr->callers = jc;
+}
+
+static typedescriptor_t *typecheck_stackbased_jsr(verifier_state *state,
+                                                                                               typedescriptor_t *stack,
+                                                                                               typedescriptor_t *stackfloor)
+{
+       typecheck_jsr_t *jsr;
+       basicblock *tbptr;
+       jitdata *jd;
+       s4 i;
+
+       jd = state->jd;
+
+       tbptr = state->iptr->sx.s23.s3.jsrtarget.block;
+       jsr = state->jsrinfos[tbptr->nr];
+
+       if (jsr && tbptr->flags == BBFINISHED) {
+
+               LOG1("another JSR to analysed subroutine L%03d", tbptr->nr);
+               if (jsr->active) {
+                       exceptions_throw_verifyerror(state->m, "Recursive JSR");
+                       return NULL;
+               }
+
+               assert(jsr->callers);
+               assert(jsr->callers->callblock);
+
+               /* copy the stack of the RET edge */
+
+               MCOPY(stackfloor, jsr->retstack, typedescriptor_t, jsr->retdepth);
+               stack = stackfloor + (jsr->retdepth - 1);
+
+               /* copy variables that were used in the subroutine from the RET edge */
+
+               for (i=0; i<state->numlocals; ++i)
+                       if (jsr->usedlocals[i])
+                               state->locals[i] = jsr->retlocals[i];
+
+               /* reach the following block */
+
+               if (!typecheck_stackbased_reach(state, state->bptr->next, stack, 
+                                       (stack - stackfloor) + 1))
+                       return NULL;
+       }
+       else {
+               if (!jsr) {
+                       LOG1("first JSR to block L%03d", tbptr->nr);
+
+                       jsr = (typecheck_jsr_t*) DumpMemory::allocate(sizeof(typecheck_jsr_t));
+                       state->jsrinfos[tbptr->nr] = jsr;
+                       jsr->callers = NULL;
+                       jsr->blockflags = (char*) DumpMemory::allocate(sizeof(char) * state->basicblockcount);
+                       jsr->retblock = NULL;
+                       jsr->start = tbptr;
+                       jsr->usedlocals = (char*) DumpMemory::allocate(sizeof(char) * state->numlocals);
+                       MZERO(jsr->usedlocals, char, state->numlocals);
+                       jsr->retlocals = (typedescriptor_t*) DumpMemory::allocate(sizeof(typedescriptor_t) * state->numlocals);
+                       jsr->retstack = (typedescriptor_t*) DumpMemory::allocate(sizeof(typedescriptor_t) * state->m->maxstack);
+                       jsr->retdepth = 0;
+               }
+               else {
+                       LOG1("re-analysing JSR to block L%03d", tbptr->nr);
+               }
+
+               jsr->active = true;
+               jsr->next = state->topjsr;
+               state->topjsr = jsr;
+
+               assert(state->iptr->sx.s23.s3.jsrtarget.block->flags == BBTYPECHECK_REACHED);
+
+               tbptr->flags = BBFINISHED;
+
+               for (tbptr = state->basicblocks; tbptr != NULL; tbptr = tbptr->next) {
+                       jsr->blockflags[tbptr->nr] = tbptr->flags;
+
+                       if (tbptr->flags == BBTYPECHECK_REACHED)
+                               tbptr->flags = BBFINISHED;
+               }
+
+               state->iptr->sx.s23.s3.jsrtarget.block->flags = BBTYPECHECK_REACHED;
+       }
+
+       /* register this block as a caller, if not already done */
+
+       typecheck_stackbased_add_jsr_caller(jsr, state->bptr);
+
+       return stack;
+}
+
+static bool typecheck_stackbased_ret(verifier_state *state,
+                                                                        typedescriptor_t *stack,
+                                                                        typedescriptor_t *stackfloor)
+{
+       basicblock *tbptr;
+       typecheck_jsr_caller_t *jsrcaller;
+       typecheck_jsr_t *jsr;
+       s4 i;
+
+       /* get the subroutine we are RETurning from */
+
+       tbptr = (basicblock*) TYPEINFO_RETURNADDRESS(state->locals[state->iptr->s1.varindex].typeinfo);
+       if (tbptr == NULL) {
+               exceptions_throw_verifyerror(state->m, "Illegal RET");
+               return false;
+       }
+
+       LOG1("RET from subroutine L%03d", tbptr->nr);
+       jsr = state->jsrinfos[tbptr->nr];
+       assert(jsr);
+
+       /* check against recursion */
+
+       if (!jsr->active) {
+               exceptions_throw_verifyerror(state->m, "RET outside of local subroutine");
+               return false;
+       }
+
+       /* check against multiple RETs for one subroutine */
+
+       if (jsr->retblock && jsr->retblock != state->bptr) {
+               exceptions_throw_verifyerror(state->m, "Multiple RETs from local subroutine");
+               return false;
+       }
+
+       /* store data-flow of the RET edge */
+
+       jsr->retblock = state->bptr;
+       jsr->retdepth = (stack - stackfloor) + 1;
+       MCOPY(jsr->retstack, stackfloor, typedescriptor_t, jsr->retdepth);
+       MCOPY(jsr->retlocals, state->locals, typedescriptor_t, state->numlocals);
+
+       /* invalidate the returnAddress used by this RET */
+       /* XXX should we also invalidate the returnAddresses of JSRs that are skipped by this RET? */
+
+       for (i=0; i<state->numlocals; ++i) {
+               typedescriptor_t *lc = &(jsr->retlocals[i]);
+               if (TYPE_IS_RETURNADDRESS(lc->type, lc->typeinfo))
+                       if (TYPEINFO_RETURNADDRESS(lc->typeinfo) == tbptr) {
+                               LOG1("invalidating returnAddress in local %d", i);
+                               TYPEINFO_INIT_RETURNADDRESS(lc->typeinfo, NULL);
+                       }
+       }
+
+       /* touch all callers of the subroutine, so they are analysed again */
+
+       for (jsrcaller = jsr->callers; jsrcaller != NULL; jsrcaller = jsrcaller->next) {
+               tbptr = jsrcaller->callblock;
+               LOG1("touching caller L%03d from RET", tbptr->nr);
+               assert(jsr->blockflags[tbptr->nr] >= BBFINISHED);
+               jsr->blockflags[tbptr->nr] = BBTYPECHECK_REACHED; /* XXX repeat? */
+       }
+
+       return true;
+}
+
+bool typecheck_stackbased(jitdata *jd)
+{
+       register verifier_slot_t *stack;
+       verifier_slot_t *stackfloor;
+       s4 len;
+       methoddesc *md;
+       bool maythrow;
+       bool superblockend;
+       verifier_slot_t temp;
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       s4 i;
+       typecheck_result r;
+       verifier_slot_t *dst;
+       verifier_state state;
+       basicblock *tbptr;
+       exception_entry *ex;
+       typedescriptor_t exstack;
+       s4 skip = 0;
+
+       DOLOG( show_method(jd, SHOW_PARSE); );
+
+       /* initialize verifier state */
+
+       state.jd = jd;
+       state.m = jd->m;
+       state.cd = jd->cd;
+       state.basicblocks = jd->basicblocks;
+       state.basicblockcount = jd->basicblockcount;
+       state.topjsr = NULL;
+#   define STATE (&state)
+
+       /* check that the basicblock numbers are valid */
+
+#if !defined(NDEBUG)
+       jit_check_basicblock_numbers(jd);
+#endif
+
+       /* check if this method is an instance initializer method */
+
+    state.initmethod = (state.m->name == utf_init);
+
+       /* allocate parameter descriptors if necessary */
+
+       if (!state.m->parseddesc->params)
+               if (!descriptor_params_from_paramtypes(state.m->parseddesc,state.m->flags))
+                       return false;
+
+       /* allocate the stack buffers */
+
+       stackfloor = (verifier_slot_t*) DumpMemory::allocate(sizeof(verifier_slot_t) * (state.m->maxstack + 1));
+       state.stackceiling = stackfloor + state.m->maxstack;
+       stack = stackfloor - 1;
+       state.indepth = (s4*) DumpMemory::allocate(sizeof(s4) * state.basicblockcount);
+       state.startstack = (verifier_slot_t*) DumpMemory::allocate(sizeof(verifier_slot_t) * state.m->maxstack * state.basicblockcount);
+
+       /* allocate the local variables buffers */
+
+       state.numlocals = state.m->maxlocals;
+       state.validlocals = state.m->maxlocals;
+    if (state.initmethod)
+               state.numlocals++; /* extra marker variable */
+
+       state.locals = (verifier_slot_t*) DumpMemory::allocate(sizeof(verifier_slot_t) * state.numlocals);
+       state.startlocals = (verifier_slot_t*) DumpMemory::allocate(sizeof(verifier_slot_t) * state.numlocals * state.basicblockcount);
+
+    /* allocate the buffer of active exception handlers */
+
+    state.handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (state.jd->exceptiontablelength + 1));
+
+    /* initialize instack of exception handlers */
+
+       exstack.type = TYPE_ADR;
+       typeinfo_init_classinfo(&(exstack.typeinfo),
+                                                       class_java_lang_Throwable); /* changed later */
+
+    LOG("Exception handler stacks set.\n");
+
+       /* initialize jsr info buffer */
+
+       state.jsrinfos = (typecheck_jsr_t**) DumpMemory::allocate(sizeof(typecheck_jsr_t*) * state.basicblockcount);
+       MZERO(state.jsrinfos, typecheck_jsr_t *, state.basicblockcount);
+
+       /* initialize stack of first block */
+
+       state.indepth[0] = 0;
+
+       /* initialize locals of first block */
+
+    /* if this is an instance method initialize the "this" ref type */
+
+    if (!(state.m->flags & ACC_STATIC)) {
+               if (state.validlocals < 1)
+                       VERIFY_ERROR("Not enough local variables for method arguments");
+               dst = state.startlocals;
+               dst->type = TYPE_ADR;
+               if (state.initmethod)
+                       TYPEINFO_INIT_NEWOBJECT(dst->typeinfo, NULL);
+               else
+                       typeinfo_init_classinfo(&(dst->typeinfo), state.m->clazz);
+
+               skip = 1;
+    }
+
+    LOG("'this' argument set.\n");
+
+       len = typedescriptors_init_from_methoddesc(state.startlocals + skip,
+                       state.m->parseddesc,
+                       state.validlocals, true, skip, &state.returntype);
+       if (len < 0)
+               return false;
+
+       /* set remaining locals to void */
+
+       for (i = skip + len; i<state.numlocals; ++i)
+               state.startlocals[i].type = TYPE_VOID;
+
+       /* initialize block flags */
+
+       typecheck_init_flags(&state, BBUNDEF);
+
+       /* iterate until fixpoint reached */
+
+       do {
+
+               state.repeat = false;
+
+               /* iterate over the basic blocks */
+
+               for (state.bptr = state.basicblocks; state.bptr != NULL; state.bptr = state.bptr->next) {
+
+                       if (state.bptr->flags != BBTYPECHECK_REACHED)
+                               continue;
+
+                       DOLOG( show_basicblock(jd, state.bptr, SHOW_PARSE); );
+
+                       /* mark this block as analysed */
+
+                       state.bptr->flags = BBFINISHED;
+
+                       /* determine the active exception handlers for this block */
+                       /* XXX could use a faster algorithm with sorted lists or  */
+                       /* something?                                             */
+                       /* XXX reuse code from variables based verifer? */
+                       len = 0;
+                       for (ex = STATE->jd->exceptiontable; ex ; ex = ex->down) {
+                               if ((ex->start->nr <= STATE->bptr->nr) && (ex->end->nr > STATE->bptr->nr)) {
+                                       LOG1("\tactive handler L%03d", ex->handler->nr);
+                                       STATE->handlers[len++] = ex;
+                               }
+                       }
+                       STATE->handlers[len] = NULL;
+
+                       /* initialize the locals */
+
+                       MCOPY(state.locals,
+                                 state.startlocals + (state.bptr->nr * state.numlocals),
+                                 verifier_slot_t, state.numlocals);
+
+                       /* initialize the stack */
+
+                       len = state.indepth[state.bptr->nr];
+
+                       MCOPY(stackfloor,
+                                 state.startstack + (state.bptr->nr * state.m->maxstack),
+                                 verifier_slot_t, len);
+
+                       stack = stackfloor + (len - 1);
+
+                       /* iterate over the instructions in this block */
+
+                       state.iptr = state.bptr->iinstr;
+                       len = state.bptr->icount;
+
+                       superblockend = false;
+
+                       for (; len--; state.iptr++) {
+
+                               maythrow = false;
+
+                               LOGNL;
+                               DOLOG( typecheck_stackbased_show_state(&state, stack, stackfloor, true); );
+
+                               switch (state.iptr->opc) {
+#define TYPECHECK_STACKBASED 1
+#define STATE (&state)
+#define IPTR state.iptr
+#define BPTR state.bptr
+#define METHOD state.m
+#define LOCAL_SLOT(index)  (state.locals + (index))
+#define EXCEPTION                                                    \
+    do {                                                             \
+        LOG("EXCEPTION THROWN!\n");                                  \
+        return false;                                                \
+    } while (0)
+
+#include <typecheck-stackbased-gen.inc>
+#undef  TYPECHECK_STACKBASED
+                               }
+
+                               /* reach exception handlers for this instruction */
+
+                               if (maythrow) {
+                                       TYPECHECK_COUNT(stat_ins_maythrow);
+                                       TYPECHECK_MARK(STATE->stat_maythrow);
+                                       LOG("\treaching exception handlers");
+                                       i = 0;
+                                       while (STATE->handlers[i]) {
+                                               TYPECHECK_COUNT(stat_handlers_reached);
+                                               if (STATE->handlers[i]->catchtype.any)
+                                                       exstack.typeinfo.typeclass = STATE->handlers[i]->catchtype;
+                                               else
+                                                       exstack.typeinfo.typeclass.cls = class_java_lang_Throwable;
+                                               if (!typecheck_stackbased_reach(
+                                                               STATE,
+                                                               STATE->handlers[i]->handler,
+                                                               &exstack, 1))
+                                                       EXCEPTION;
+                                               i++;
+                                       }
+                               }
+                       }
+
+                       /* propagate types to the following block */
+
+                       if (!superblockend) {
+                               if (!typecheck_stackbased_reach(&state, state.bptr->next,
+                                                                                               stack, stack - stackfloor + 1))
+                                       EXCEPTION;
+                       }
+               } /* end loop over blocks */
+
+               while (!state.repeat && state.topjsr) {
+                       LOG1("done analysing subroutine L%03d", state.topjsr->start->nr);
+
+                       /* propagate down used locals */
+
+                       if (state.topjsr->next) {
+                               for (i=0; i<state.numlocals; ++i)
+                                       state.topjsr->next->usedlocals[i] |= state.topjsr->usedlocals[i];
+                       }
+
+                       /* restore REACHED flags */
+
+                       for (tbptr = state.basicblocks; tbptr != NULL; tbptr = tbptr->next) {
+                               assert(tbptr->flags != BBTYPECHECK_REACHED);
+                               if (state.topjsr->blockflags[tbptr->nr] == BBTYPECHECK_REACHED) {
+                                       tbptr->flags = BBTYPECHECK_REACHED;
+                                       state.repeat = true;
+                               }
+                       }
+
+                       /* dactivate the subroutine */
+
+                       state.topjsr->active = false;
+                       state.topjsr = state.topjsr->next;
+               }
+       } while (state.repeat);
+
+       /* reset block flags */
+
+       typecheck_reset_flags(&state);
+
+       LOG("typecheck_stackbased successful");
+
+       return true;
+
+throw_stack_underflow:
+       LOG("STACK UNDERFLOW!");
+       exceptions_throw_verifyerror(state.m, "Unable to pop operand off an empty stack");
+       return false;
+
+throw_stack_overflow:
+       LOG("STACK OVERFLOW!");
+       exceptions_throw_verifyerror(state.m, "Stack size too large");
+       return false;
+
+throw_stack_type_error:
+       LOG("STACK TYPE ERROR!");
+       exceptions_throw_verifyerror(state.m, "Mismatched stack types");
+       return false;
+
+throw_local_type_error:
+       LOG("LOCAL TYPE ERROR!");
+       exceptions_throw_verifyerror(state.m, "Local variable type mismatch");
+       return false;
+
+throw_stack_category_error:
+       LOG("STACK CATEGORY ERROR!");
+       exceptions_throw_verifyerror(state.m, "Attempt to split long or double on the stack");
+       return false;
+}
+
+
+#if defined(TYPECHECK_VERBOSE)
+static void typecheck_stackbased_show_state(verifier_state *state,
+                                                                                       typedescriptor_t *stack,
+                                                                                       typedescriptor_t *stackfloor,
+                                                                                       bool showins)
+{
+       typedescriptor_t *sp;
+       s4 i;
+
+       LOGSTR1("stackdepth %d stack [", (stack - stackfloor) + 1);
+       for (sp=stackfloor; sp <= stack; sp++) {
+               LOGSTR(" ");
+               DOLOG( typedescriptor_print(stdout, sp); );
+       }
+       LOGSTR(" ] locals [");
+       for (i=0; i<state->numlocals; ++i) {
+               LOGSTR(" ");
+               DOLOG( typedescriptor_print(stdout, state->locals + i); );
+       }
+       LOGSTR(" ]");
+       LOGNL;
+       if (showins && state->iptr < (state->bptr->iinstr + state->bptr->icount)) {
+               LOGSTR("\t");
+               DOLOG( show_icmd(state->jd, state->iptr, false, SHOW_PARSE); );
+               LOGNL;
+       }
+}
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/*
+ * 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/jit/verify/typecheck-typeinferer.c b/src/vm/jit/verify/typecheck-typeinferer.c
deleted file mode 100644 (file)
index 8dfbd4f..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/* src/vm/jit/verify/typecheck-typeinferer.c - type inference pass
-
-   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 "vm/types.h"
-#include "vm/global.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "mm/memory.h"
-
-#include "native/native.hpp"
-
-#include "toolbox/logging.h"
-
-#include "vm/access.h"
-#include "vm/array.hpp"
-#include "vm/jit/builtin.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/globals.hpp"
-#include "vm/loader.hpp"
-#include "vm/options.h"
-#include "vm/primitive.hpp"
-#include "vm/resolve.hpp"
-#include "vm/vm.hpp"
-
-#include "vm/jit/jit.hpp"
-#include "vm/jit/show.hpp"
-#include "vm/jit/parse.h"
-
-#include "vm/jit/verify/typecheck-typeinferer.h"
-
-#define TYPECHECK_NO_STATISTICS
-#include <typecheck-common.h>
-
-
-/* macros used by the generated code ******************************************/
-
-#define EXCEPTION          do { return false; } while (0)
-#define VERIFY_ERROR(msg)  assert(false)
-
-#define CHECK_LOCAL_TYPE(index, t)                                   \
-       assert(jd->var[(index)].type == (t));
-
-#define STORE_LOCAL(t, index)                                        \
-    do {                                                             \
-         typevector_store(jd->var, (index), (t), NULL);              \
-    } while (0)
-
-#define STORE_LOCAL_2_WORD(t, index)                                 \
-    do {                                                             \
-         typevector_store(jd->var, (index), (t), NULL);              \
-    } while (0)
-
-#define REACH_BLOCK(target)                                          \
-    do {                                                             \
-        if (!typestate_reach(state, (target),                        \
-                             state->bptr->outvars, jd->var,          \
-                             state->bptr->outdepth))                 \
-                return false;                                        \
-    } while (0)
-
-#define REACH(target)   REACH_BLOCK((target).block)
-
-#define TYPECHECK_INT(v)  assert(jd->var[(v)].type == TYPE_INT)
-#define TYPECHECK_ADR(v)  assert(jd->var[(v)].type == TYPE_ADR)
-
-
-/* handle_fieldaccess **********************************************************
-   Verify an ICMD_{GET,PUT}{STATIC,FIELD}(CONST)?
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_fieldaccess(verifier_state *state, 
-                                  varinfo *instance,
-                                  varinfo *value)
-{
-       jitdata *jd;
-
-       jd = state->jd;
-
-#define TYPECHECK_TYPEINFERER
-#include <typecheck-fields.inc>
-#undef  TYPECHECK_TYPEINFERER
-
-       return true;
-}
-
-
-/* handle_invocation ***********************************************************
-   Verify an ICMD_INVOKE* instruction.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_invocation(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_TYPEINFERER
-#define OP1   VAR(state->iptr->sx.s23.s2.args[0])
-#include <typecheck-invoke.inc>
-#undef  OP1
-#undef  TYPECHECK_TYPEINFERER
-
-       return true;
-}
-
-
-/* handle_builtin **************************************************************
-   Verify the call of a builtin method.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_builtin(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_TYPEINFERER
-#define OP1   state->iptr->sx.s23.s2.args[0]
-#include <typecheck-builtins.inc>
-#undef  OP1
-#undef  TYPECHECK_TYPEINFERER
-
-       return true;
-}
-
-/* handle_multianewarray *******************************************************
-   Verify a MULTIANEWARRAY instruction.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_multianewarray(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_TYPEINFERER
-#include <typecheck-multianewarray.inc>
-#undef  TYPECHECK_TYPEINFERER
-
-       return true;
-}
-
-
-/* handle_basic_block **********************************************************
-   Perform bytecode verification of a basic block.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_basic_block(verifier_state *state)
-{
-    int opcode;                                      /* current opcode */
-    int len;                        /* for counting instructions, etc. */
-    bool superblockend;        /* true if no fallthrough to next block */
-       instruction *iptr;                      /* the current instruction */
-    basicblock *tbptr;                   /* temporary for target block */
-    bool maythrow;               /* true if this instruction may throw */
-       s4 i;
-       branch_target_t *table;
-       lookup_target_t *lookup;
-       jitdata *jd = state->jd;
-       exception_entry *ex;
-
-       LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",state->bptr->nr);
-       LOGFLUSH;
-       DOLOG(show_basicblock(jd, state->bptr, SHOW_STACK));
-
-       superblockend = false;
-       state->bptr->flags = BBFINISHED;
-
-       /* prevent compiler warnings */
-
-
-       /* determine the active exception handlers for this block */
-       /* XXX could use a faster algorithm with sorted lists or  */
-       /* something?                                             */
-       len = 0;
-       for (ex = state->jd->exceptiontable; ex ; ex = ex->down) {
-               if ((ex->start->nr <= state->bptr->nr) && (ex->end->nr > state->bptr->nr)) {
-                       LOG1("active handler L%03d", ex->handler->nr);
-                       state->handlers[len++] = ex;
-               }
-       }
-       state->handlers[len] = NULL;
-
-       /* init variable types at the start of this block */
-       typevector_copy_inplace(state->bptr->inlocals, jd->var, state->numlocals);
-
-       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->invars, 
-                               state->bptr->indepth));
-       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-       LOGNL; LOGFLUSH;
-
-       /* loop over the instructions */
-       len = state->bptr->icount;
-       state->iptr = state->bptr->iinstr;
-       while (--len >= 0)  {
-               TYPECHECK_COUNT(stat_ins);
-
-               iptr = state->iptr;
-
-               DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-               LOGNL; LOGFLUSH;
-               DOLOG(show_icmd(jd, state->iptr, false, SHOW_STACK)); LOGNL; LOGFLUSH;
-
-               opcode = iptr->opc;
-               maythrow = false;
-
-               switch (opcode) {
-
-                       /* include generated code for ICMDs verification */
-
-#define TYPECHECK_TYPEINFERER
-#define STATE  state
-#define METHOD (state->m)
-#define IPTR   iptr
-#define BPTR   (state->bptr)
-#include <typecheck-typeinferer-gen.inc>
-#undef  STATE
-#undef  METHOD
-#undef  IPTR
-#undef  BPTR
-#undef  TYPECHECK_TYPEINFERER
-
-                       default:
-                               vm_abort("missing ICMD in type inferer: %d\n", opcode);
-               }
-
-               /* reach exception handlers for this instruction */
-
-               if (maythrow) {
-                       TYPECHECK_COUNT(stat_ins_maythrow);
-                       TYPECHECK_MARK(state->stat_maythrow);
-                       LOG("reaching exception handlers");
-                       i = 0;
-                       while (state->handlers[i]) {
-                               TYPECHECK_COUNT(stat_handlers_reached);
-                               if (state->handlers[i]->catchtype.any)
-                                       VAR(state->exinvars)->typeinfo.typeclass = state->handlers[i]->catchtype;
-                               else
-                                       VAR(state->exinvars)->typeinfo.typeclass.cls = class_java_lang_Throwable;
-                               if (!typestate_reach(state,
-                                               state->handlers[i]->handler,
-                                               &(state->exinvars), jd->var, 1))
-                                       return false;
-                               i++;
-                       }
-               }
-
-               LOG("\t\tnext instruction");
-               state->iptr++;
-       } /* while instructions */
-
-       LOG("instructions done");
-       LOGSTR("RESULT=> ");
-       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->outvars,
-                               state->bptr->outdepth));
-       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-       LOGNL; LOGFLUSH;
-
-       /* propagate stack and variables to the following block */
-       if (!superblockend) {
-               LOG("reaching following block");
-               tbptr = state->bptr->next;
-               while (tbptr->flags == BBDELETED) {
-                       tbptr = tbptr->next;
-               }
-               if (!typestate_reach(state,tbptr,state->bptr->outvars, jd->var,
-                                       state->bptr->outdepth))
-                       return false;
-       }
-
-       return true;
-}
-
-
-bool typecheck_infer_types(jitdata *jd)
-{
-       methodinfo     *meth;
-       codegendata    *cd;
-       varinfo        *savedlocals;
-       verifier_state  state;             /* current state of the verifier */
-
-       /* get required compiler data */
-
-       meth = jd->m;
-       cd   = jd->cd;
-
-       /* some logging on entry */
-
-
-    LOGSTR("\n==============================================================================\n");
-    DOLOG( show_method(jd, SHOW_STACK) );
-    LOGSTR("\n==============================================================================\n");
-    LOGMETHOD("Entering type inference: ",cd->method);
-
-       /* initialize the verifier state */
-
-       state.m = meth;
-       state.jd = jd;
-       state.cd = cd;
-       state.basicblockcount = jd->basicblockcount;
-       state.basicblocks = jd->basicblocks;
-       state.savedindices = NULL;
-       state.savedinvars = NULL;
-
-       /* check that the basicblock numbers are valid */
-
-#if !defined(NDEBUG)
-       jit_check_basicblock_numbers(jd);
-#endif
-
-       /* check if this method is an instance initializer method */
-
-    state.initmethod = (state.m->name == utf_init);
-
-       /* initialize the basic block flags for the following CFG traversal */
-
-       typecheck_init_flags(&state, BBFINISHED);
-
-    /* number of local variables */
-    
-    /* In <init> methods we use an extra local variable to indicate whether */
-    /* the 'this' reference has been initialized.                           */
-       /*         TYPE_VOID...means 'this' has not been initialized,           */
-       /*         TYPE_INT....means 'this' has been initialized.               */
-
-    state.numlocals = state.jd->localcount;
-       state.validlocals = state.numlocals;
-    if (state.initmethod) 
-               state.numlocals++; /* VERIFIER_EXTRA_LOCALS */
-
-    /* allocate the buffer of active exception handlers */
-       
-    state.handlers = DMNEW(exception_entry*, state.jd->exceptiontablelength + 1);
-
-       /* save local variables */
-
-       savedlocals = DMNEW(varinfo, state.numlocals);
-       MCOPY(savedlocals, jd->var, varinfo, state.numlocals);
-
-       /* initialized local variables of first block */
-
-       if (!typecheck_init_locals(&state, false))
-               return false;
-
-    /* initialize invars of exception handlers */
-       
-       state.exinvars = state.numlocals;
-       VAR(state.exinvars)->type = TYPE_ADR;
-       typeinfo_init_classinfo(&(VAR(state.exinvars)->typeinfo),
-                                                       class_java_lang_Throwable); /* changed later */
-
-    LOG("Exception handler stacks set.\n");
-
-    /* loop while there are still blocks to be checked */
-    do {
-               TYPECHECK_COUNT(count_iterations);
-
-        state.repeat = false;
-        
-        state.bptr = state.basicblocks;
-
-        for (; state.bptr; state.bptr = state.bptr->next) {
-            LOGSTR1("---- BLOCK %04d, ",state.bptr->nr);
-            LOGSTR1("blockflags: %d\n",state.bptr->flags);
-            LOGFLUSH;
-            
-                   /* verify reached block */  
-            if (state.bptr->flags == BBTYPECHECK_REACHED) {
-                if (!handle_basic_block(&state))
-                                       return false;
-            }
-        } /* for blocks */
-
-        LOGIF(state.repeat,"state.repeat == true");
-    } while (state.repeat);
-
-       /* statistics */
-       
-       /* reset the flags of blocks we haven't reached */
-
-       typecheck_reset_flags(&state);
-
-       /* restore locals */
-
-       MCOPY(jd->var, savedlocals, varinfo, state.numlocals);
-
-       /* everything's ok */
-
-    LOGimp("exiting type inference");
-       return true;
-}
-
-/*
- * 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/jit/verify/typecheck-typeinferer.cpp b/src/vm/jit/verify/typecheck-typeinferer.cpp
new file mode 100644 (file)
index 0000000..7626890
--- /dev/null
@@ -0,0 +1,492 @@
+/* src/vm/jit/verify/typecheck-typeinferer.c - type inference pass
+
+   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 "vm/types.h"
+#include "vm/global.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "mm/memory.h"
+
+#include "native/native.hpp"
+
+#include "toolbox/logging.h"
+
+#include "vm/access.hpp"
+#include "vm/array.hpp"
+#include "vm/jit/builtin.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/globals.hpp"
+#include "vm/loader.hpp"
+#include "vm/options.h"
+#include "vm/primitive.hpp"
+#include "vm/resolve.hpp"
+#include "vm/vm.hpp"
+
+#include "vm/jit/jit.hpp"
+#include "vm/jit/show.hpp"
+#include "vm/jit/parse.hpp"
+
+#include "vm/jit/verify/typecheck-typeinferer.hpp"
+
+#define TYPECHECK_NO_STATISTICS
+#include "vm/jit/verify/typecheck-common.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* macros used by the generated code ******************************************/
+
+#define EXCEPTION          do { return false; } while (0)
+#define VERIFY_ERROR(msg)  assert(false)
+
+#define CHECK_LOCAL_TYPE(index, t)                                   \
+       assert(jd->var[(index)].type == (t));
+
+#define STORE_LOCAL(t, index)                                        \
+    do {                                                             \
+         typevector_store(jd->var, (index), (t), NULL);              \
+    } while (0)
+
+#define STORE_LOCAL_2_WORD(t, index)                                 \
+    do {                                                             \
+         typevector_store(jd->var, (index), (t), NULL);              \
+    } while (0)
+
+#define REACH_BLOCK(target)                                          \
+    do {                                                             \
+        if (!typestate_reach(state, (target),                        \
+                             state->bptr->outvars, jd->var,          \
+                             state->bptr->outdepth))                 \
+                return false;                                        \
+    } while (0)
+
+#define REACH(target)   REACH_BLOCK((target).block)
+
+#define TYPECHECK_INT(v)  assert(jd->var[(v)].type == TYPE_INT)
+#define TYPECHECK_ADR(v)  assert(jd->var[(v)].type == TYPE_ADR)
+
+
+/* handle_fieldaccess **********************************************************
+   Verify an ICMD_{GET,PUT}{STATIC,FIELD}(CONST)?
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_fieldaccess(verifier_state *state, 
+                                  varinfo *instance,
+                                  varinfo *value)
+{
+       jitdata *jd;
+
+       jd = state->jd;
+
+#define TYPECHECK_TYPEINFERER
+#include <typecheck-fields.inc>
+#undef  TYPECHECK_TYPEINFERER
+
+       return true;
+}
+
+
+/* handle_invocation ***********************************************************
+   Verify an ICMD_INVOKE* instruction.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_invocation(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_TYPEINFERER
+#define OP1   VAR(state->iptr->sx.s23.s2.args[0])
+#include <typecheck-invoke.inc>
+#undef  OP1
+#undef  TYPECHECK_TYPEINFERER
+
+       return true;
+}
+
+
+/* handle_builtin **************************************************************
+   Verify the call of a builtin method.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_builtin(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_TYPEINFERER
+#define OP1   state->iptr->sx.s23.s2.args[0]
+#include <typecheck-builtins.inc>
+#undef  OP1
+#undef  TYPECHECK_TYPEINFERER
+
+       return true;
+}
+
+/* handle_multianewarray *******************************************************
+   Verify a MULTIANEWARRAY instruction.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_multianewarray(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_TYPEINFERER
+#include <typecheck-multianewarray.inc>
+#undef  TYPECHECK_TYPEINFERER
+
+       return true;
+}
+
+
+/* handle_basic_block **********************************************************
+   Perform bytecode verification of a basic block.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_basic_block(verifier_state *state)
+{
+    int opcode;                                      /* current opcode */
+    int len;                        /* for counting instructions, etc. */
+    bool superblockend;        /* true if no fallthrough to next block */
+       instruction *iptr;                      /* the current instruction */
+    basicblock *tbptr;                   /* temporary for target block */
+    bool maythrow;               /* true if this instruction may throw */
+       s4 i;
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       jitdata *jd = state->jd;
+       exception_entry *ex;
+
+       LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",state->bptr->nr);
+       LOGFLUSH;
+       DOLOG(show_basicblock(jd, state->bptr, SHOW_STACK));
+
+       superblockend = false;
+       state->bptr->flags = BBFINISHED;
+
+       /* prevent compiler warnings */
+
+
+       /* determine the active exception handlers for this block */
+       /* XXX could use a faster algorithm with sorted lists or  */
+       /* something?                                             */
+       len = 0;
+       for (ex = state->jd->exceptiontable; ex ; ex = ex->down) {
+               if ((ex->start->nr <= state->bptr->nr) && (ex->end->nr > state->bptr->nr)) {
+                       LOG1("active handler L%03d", ex->handler->nr);
+                       state->handlers[len++] = ex;
+               }
+       }
+       state->handlers[len] = NULL;
+
+       /* init variable types at the start of this block */
+       typevector_copy_inplace(state->bptr->inlocals, jd->var, state->numlocals);
+
+       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->invars, 
+                               state->bptr->indepth));
+       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+       LOGNL; LOGFLUSH;
+
+       /* loop over the instructions */
+       len = state->bptr->icount;
+       state->iptr = state->bptr->iinstr;
+       while (--len >= 0)  {
+               TYPECHECK_COUNT(stat_ins);
+
+               iptr = state->iptr;
+
+               DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+               LOGNL; LOGFLUSH;
+               DOLOG(show_icmd(jd, state->iptr, false, SHOW_STACK)); LOGNL; LOGFLUSH;
+
+               opcode = iptr->opc;
+               maythrow = false;
+
+               switch (opcode) {
+
+                       /* include generated code for ICMDs verification */
+
+#define TYPECHECK_TYPEINFERER
+#define STATE  state
+#define METHOD (state->m)
+#define IPTR   iptr
+#define BPTR   (state->bptr)
+#include <typecheck-typeinferer-gen.inc>
+#undef  STATE
+#undef  METHOD
+#undef  IPTR
+#undef  BPTR
+#undef  TYPECHECK_TYPEINFERER
+
+                       default:
+                               vm_abort("missing ICMD in type inferer: %d\n", opcode);
+               }
+
+               /* reach exception handlers for this instruction */
+
+               if (maythrow) {
+                       TYPECHECK_COUNT(stat_ins_maythrow);
+                       TYPECHECK_MARK(state->stat_maythrow);
+                       LOG("reaching exception handlers");
+                       i = 0;
+                       while (state->handlers[i]) {
+                               TYPECHECK_COUNT(stat_handlers_reached);
+                               if (state->handlers[i]->catchtype.any)
+                                       VAR(state->exinvars)->typeinfo.typeclass = state->handlers[i]->catchtype;
+                               else
+                                       VAR(state->exinvars)->typeinfo.typeclass.cls = class_java_lang_Throwable;
+                               if (!typestate_reach(state,
+                                               state->handlers[i]->handler,
+                                               &(state->exinvars), jd->var, 1))
+                                       return false;
+                               i++;
+                       }
+               }
+
+               LOG("\t\tnext instruction");
+               state->iptr++;
+       } /* while instructions */
+
+       LOG("instructions done");
+       LOGSTR("RESULT=> ");
+       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->outvars,
+                               state->bptr->outdepth));
+       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+       LOGNL; LOGFLUSH;
+
+       /* propagate stack and variables to the following block */
+       if (!superblockend) {
+               LOG("reaching following block");
+               tbptr = state->bptr->next;
+               while (tbptr->flags == BBDELETED) {
+                       tbptr = tbptr->next;
+               }
+               if (!typestate_reach(state,tbptr,state->bptr->outvars, jd->var,
+                                       state->bptr->outdepth))
+                       return false;
+       }
+
+       return true;
+}
+
+
+bool typecheck_infer_types(jitdata *jd)
+{
+       methodinfo     *meth;
+       codegendata    *cd;
+       varinfo        *savedlocals;
+       verifier_state  state;             /* current state of the verifier */
+
+       /* get required compiler data */
+
+       meth = jd->m;
+       cd   = jd->cd;
+
+       /* some logging on entry */
+
+
+    LOGSTR("\n==============================================================================\n");
+    DOLOG( show_method(jd, SHOW_STACK) );
+    LOGSTR("\n==============================================================================\n");
+    LOGMETHOD("Entering type inference: ",cd->method);
+
+       /* initialize the verifier state */
+
+       state.m = meth;
+       state.jd = jd;
+       state.cd = cd;
+       state.basicblockcount = jd->basicblockcount;
+       state.basicblocks = jd->basicblocks;
+       state.savedindices = NULL;
+       state.savedinvars = NULL;
+
+       /* check that the basicblock numbers are valid */
+
+#if !defined(NDEBUG)
+       jit_check_basicblock_numbers(jd);
+#endif
+
+       /* check if this method is an instance initializer method */
+
+    state.initmethod = (state.m->name == utf_init);
+
+       /* initialize the basic block flags for the following CFG traversal */
+
+       typecheck_init_flags(&state, BBFINISHED);
+
+    /* number of local variables */
+    
+    /* In <init> methods we use an extra local variable to indicate whether */
+    /* the 'this' reference has been initialized.                           */
+       /*         TYPE_VOID...means 'this' has not been initialized,           */
+       /*         TYPE_INT....means 'this' has been initialized.               */
+
+    state.numlocals = state.jd->localcount;
+       state.validlocals = state.numlocals;
+    if (state.initmethod) 
+               state.numlocals++; /* VERIFIER_EXTRA_LOCALS */
+
+    /* allocate the buffer of active exception handlers */
+       
+    state.handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (state.jd->exceptiontablelength + 1));
+
+       /* save local variables */
+
+       savedlocals = (varinfo*) DumpMemory::allocate(sizeof(varinfo) * state.numlocals);
+       MCOPY(savedlocals, jd->var, varinfo, state.numlocals);
+
+       /* initialized local variables of first block */
+
+       if (!typecheck_init_locals(&state, false))
+               return false;
+
+    /* initialize invars of exception handlers */
+       
+       state.exinvars = state.numlocals;
+       VAR(state.exinvars)->type = TYPE_ADR;
+       typeinfo_init_classinfo(&(VAR(state.exinvars)->typeinfo),
+                                                       class_java_lang_Throwable); /* changed later */
+
+    LOG("Exception handler stacks set.\n");
+
+    /* loop while there are still blocks to be checked */
+    do {
+               TYPECHECK_COUNT(count_iterations);
+
+        state.repeat = false;
+        
+        state.bptr = state.basicblocks;
+
+        for (; state.bptr; state.bptr = state.bptr->next) {
+            LOGSTR1("---- BLOCK %04d, ",state.bptr->nr);
+            LOGSTR1("blockflags: %d\n",state.bptr->flags);
+            LOGFLUSH;
+            
+                   /* verify reached block */  
+            if (state.bptr->flags == BBTYPECHECK_REACHED) {
+                if (!handle_basic_block(&state))
+                                       return false;
+            }
+        } /* for blocks */
+
+        LOGIF(state.repeat,"state.repeat == true");
+    } while (state.repeat);
+
+       /* statistics */
+       
+       /* reset the flags of blocks we haven't reached */
+
+       typecheck_reset_flags(&state);
+
+       /* restore locals */
+
+       MCOPY(jd->var, savedlocals, varinfo, state.numlocals);
+
+       /* everything's ok */
+
+    LOGimp("exiting type inference");
+       return true;
+}
+
+#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/jit/verify/typecheck-typeinferer.h b/src/vm/jit/verify/typecheck-typeinferer.h
deleted file mode 100644 (file)
index 6684ac9..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* src/vm/jit/verify/typecheck-typeinferer.h - type inference header
-
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
-   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
-   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
-   J. Wenninger, Institut f. Computersprachen - TU Wien
-
-   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.
-
-   Contact: cacao@cacaojvm.org
-
-   Authors: Edwin Steiner
-
-
-*/
-
-
-#ifndef _TYPECHECK_TYPEINFERER_H
-#define _TYPECHECK_TYPEINFERER_H
-
-#include "config.h"
-
-#include "vm/global.h"
-#include "vm/jit/jit.hpp"
-
-
-/* function prototypes ********************************************************/
-
-#if defined(ENABLE_VERIFIER)
-bool typecheck_infer_types(jitdata *jd);
-#endif
-
-#endif /* _TYPECHECK_TYPEINFERER_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/jit/verify/typecheck-typeinferer.hpp b/src/vm/jit/verify/typecheck-typeinferer.hpp
new file mode 100644 (file)
index 0000000..a3e79b8
--- /dev/null
@@ -0,0 +1,69 @@
+/* src/vm/jit/verify/typecheck-typeinferer.h - type inference header
+
+   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+   J. Wenninger, Institut f. Computersprachen - TU Wien
+
+   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.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Edwin Steiner
+
+
+*/
+
+
+#ifndef _TYPECHECK_TYPEINFERER_H
+#define _TYPECHECK_TYPEINFERER_H
+
+#include "config.h"
+
+#include "vm/global.h"
+#include "vm/jit/jit.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* function prototypes ********************************************************/
+
+#if defined(ENABLE_VERIFIER)
+bool typecheck_infer_types(jitdata *jd);
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _TYPECHECK_TYPEINFERER_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/jit/verify/typecheck.c b/src/vm/jit/verify/typecheck.c
deleted file mode 100644 (file)
index 842f89f..0000000
+++ /dev/null
@@ -1,833 +0,0 @@
-/* src/vm/jit/verify/typecheck.c - typechecking (part of bytecode verification)
-
-   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.
-
-*/
-
-/*
-
-What's the purpose of the `typechecker`?
-----------------------------------------
-
-The typechecker analyses (the intermediate repr. of) the bytecode of
-each method and ensures that for each instruction the values on the
-stack and in local variables are of the correct type whenever the
-instruction is executed.
-
-type checking is a mandatory part of bytecode verification.
-
-
-How does the typechecker work?
-------------------------------
-
-The JVM stack and the local variables are not statically typed, so the
-typechecker has to *infer* the static types of stack slots and local
-variables at each point of the method. The JVM spec imposes a lot of
-restrictions on the bytecode in order to guarantee that this is always
-possible.
-
-Basically the typechecker solves the data flow equations of the method.
-This is done in the usual way for a forward data flow analysis: Starting
-from the entry point of the method the typechecker follows the CFG and
-records the type of each stack slot and local variable at each point[1].
-When two or more control flow paths merge at a point, the union of the
-types for each slot/variable is taken. The algorithm continues to follow
-all possible paths[2] until the recorded types do not change anymore (ie.
-the equations have been solved).
-
-If the solution has been reached and the resulting types are valid for
-all instructions, then type checking terminates with success, otherwise
-an exception is thrown.
-
-
-Why is this code so damn complicated?
--------------------------------------
-
-Short answer: The devil's in the details.
-
-While the basic operation of the typechecker is no big deal, there are
-many properties of Java bytecode which make type checking hard. Some of
-them are not even addressed in the JVM spec. Some problems and their
-solutions:
-
-*) Finding a good representation of the union of two reference types is
-difficult because of multiple inheritance of interfaces. 
-
-       Solution: The typeinfo system can represent such "merged" types by a
-       list of proper subclasses of a class. Example:
-
-               typeclass=java.lang.Object merged={ InterfaceA, InterfaceB }
-       
-       represents the result of merging two interface types "InterfaceA"
-       and "InterfaceB".
-
-*) When the code of a method is verified, there may still be unresolved
-references to classes/methods/fields in the code, which we may not force
-to be resolved eagerly. (A similar problem arises because of the special
-checks for protected members.)
-
-       Solution: The typeinfo system knows how to deal with unresolved
-       class references. Whenever a check has to be performed for an
-       unresolved type, the type is annotated with constraints representing
-       the check. Later, when the type is resolved, the constraints are
-       checked. (See the constrain_unresolved_... and the resolve_...
-       methods.)[3]
-
-*) Checks for uninitialized object instances are hard because after the
-invocation of <init> on an uninitialized object *all* slots/variables
-referring to this object (and exactly those slots/variables) must be
-marked as initialized.
-
-       Solution: The JVM spec describes a solution, which has been
-       implemented in this typechecker.
-
-Note that some checks mentioned in the JVM spec are unnecessary[4] and
-not performed by either the reference implementation, or this implementation.
-
-
---- Footnotes
-
-[1] Actually only the types of slots/variables at the start of each
-basic block are remembered. Within a basic block the algorithm only keeps
-the types of the slots/variables for the "current" instruction which is
-being analysed. 
-
-[2] Actually the algorithm iterates through the basic block list until
-there are no more changes. Theoretically it would be wise to sort the
-basic blocks topologically beforehand, but the number of average/max
-iterations observed is so low, that this was not deemed necessary.
-
-[3] This is similar to a method proposed by: Alessandro Coglio et al., A
-Formal Specification of Java Class Loading, Technical Report, Kestrel
-Institute April 2000, revised July 2000 
-http://www.kestrel.edu/home/people/coglio/loading.pdf
-An important difference is that Coglio's subtype constraints are checked
-after loading, while our constraints are checked when the field/method
-is accessed for the first time, so we can guarantee lexically correct
-error reporting.
-
-[4] Alessandro Coglio
-    Improving the official specification of Java bytecode verification
-    Proceedings of the 3rd ECOOP Workshop on Formal Techniques for Java Programs
-    June 2001
-    citeseer.ist.psu.edu/article/coglio03improving.html
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "vm/types.h"
-
-#ifdef ENABLE_VERIFIER
-
-#include "mm/memory.h"
-
-#include "native/native.hpp"
-
-#include "toolbox/logging.h"
-
-#include "vm/access.h"
-#include "vm/array.hpp"
-#include "vm/jit/builtin.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/global.h"
-#include "vm/globals.hpp"
-#include "vm/loader.hpp"
-#include "vm/options.h"
-#include "vm/primitive.hpp"
-#include "vm/resolve.hpp"
-
-#include "vm/jit/jit.hpp"
-#include "vm/jit/parse.h"
-#include "vm/jit/show.hpp"
-
-#include <typecheck-common.h>
-
-
-/****************************************************************************/
-/* MACROS FOR VARIABLE TYPE CHECKING                                        */
-/****************************************************************************/
-
-#define TYPECHECK_CHECK_TYPE(i,tp,msg)                               \
-    do {                                                             \
-        if (VAR(i)->type != (tp)) {                                  \
-            exceptions_throw_verifyerror(state->m, (msg));           \
-            return false;                                            \
-        }                                                            \
-    } while (0)
-
-#define TYPECHECK_INT(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_INT,"Expected to find integer value")
-#define TYPECHECK_LNG(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_LNG,"Expected to find long value")
-#define TYPECHECK_FLT(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_FLT,"Expected to find float value")
-#define TYPECHECK_DBL(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_DBL,"Expected to find double value")
-#define TYPECHECK_ADR(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_ADR,"Expected to find object value")
-
-#define TYPECHECK_INT_OP(o)  TYPECHECK_INT((o).varindex)
-#define TYPECHECK_LNG_OP(o)  TYPECHECK_LNG((o).varindex)
-#define TYPECHECK_FLT_OP(o)  TYPECHECK_FLT((o).varindex)
-#define TYPECHECK_DBL_OP(o)  TYPECHECK_DBL((o).varindex)
-#define TYPECHECK_ADR_OP(o)  TYPECHECK_ADR((o).varindex)
-
-
-/* typestate_save_invars *******************************************************
-   Save the invars of the current basic block in the space reserved by
-   parse.
-
-   This function must be called before an instruction modifies a variable
-   that is an invar of the current block. In such cases the invars of the
-   block must be saved, and restored at the end of the analysis of this
-   basic block, so that the invars again reflect the *input* to this basic
-   block (and do not randomly contain types that appear within the block).
-
-   IN:
-       state............current state of the verifier
-
-*******************************************************************************/
-
-static void
-typestate_save_invars(verifier_state *state)
-{
-       s4 i, index;
-       s4 *pindex;
-       
-       LOG("saving invars");
-
-       if (!state->savedindices) {
-               LOG("allocating savedindices buffer");
-               pindex = DMNEW(s4, state->m->maxstack);
-               state->savedindices = pindex;
-               index = state->numlocals + VERIFIER_EXTRA_VARS;
-               for (i=0; i<state->m->maxstack; ++i)
-                       *pindex++ = index++;
-       }
-
-       /* save types */
-
-       typecheck_copy_types(state, state->bptr->invars, state->savedindices, 
-                       state->bptr->indepth);
-
-       /* set the invars of the block to the saved variables */
-       /* and remember the original invars                   */
-
-       state->savedinvars = state->bptr->invars;
-       state->bptr->invars = state->savedindices;
-}
-
-
-/* typestate_restore_invars  ***************************************************
-   Restore the invars of the current basic block that have been previously
-   saved by `typestate_save_invars`.
-
-   IN:
-       state............current state of the verifier
-
-*******************************************************************************/
-
-static void
-typestate_restore_invars(verifier_state *state)
-{
-       TYPECHECK_COUNT(stat_savedstack);
-       LOG("restoring saved invars");
-
-       /* restore the invars pointer */
-
-       state->bptr->invars = state->savedinvars;
-
-       /* copy the types back */
-
-       typecheck_copy_types(state, state->savedindices, state->bptr->invars,
-                       state->bptr->indepth);
-
-       /* mark that there are no saved invars currently */
-
-       state->savedinvars = NULL;
-}
-
-
-/* handle_fieldaccess **********************************************************
-   Verify an ICMD_{GET,PUT}{STATIC,FIELD}(CONST)?
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_fieldaccess(verifier_state *state,
-                                  varinfo *instance,
-                                  varinfo *value)
-{
-       jitdata *jd;
-
-       jd = state->jd;
-
-#define TYPECHECK_VARIABLESBASED
-#define EXCEPTION  do { return false; } while (0)
-#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
-#include <typecheck-fields.inc>
-#undef  EXCEPTION
-#undef  VERIFY_ERROR
-#undef  TYPECHECK_VARIABLESBASED
-
-       return true;
-}
-
-
-/* handle_invocation ***********************************************************
-   Verify an ICMD_INVOKE* instruction.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_invocation(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_VARIABLESBASED
-#define OP1   VAR(state->iptr->sx.s23.s2.args[0])
-#include <typecheck-invoke.inc>
-#undef  OP1
-#undef  TYPECHECK_VARIABLESBASED
-
-       return true;
-}
-
-
-/* handle_builtin **************************************************************
-   Verify the call of a builtin method.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_builtin(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_VARIABLESBASED
-#define OP1   state->iptr->sx.s23.s2.args[0]
-#include <typecheck-builtins.inc>
-#undef  OP1
-#undef  TYPECHECK_VARIABLESBASED
-
-       return true;
-}
-
-/* handle_multianewarray *******************************************************
-   Verify a MULTIANEWARRAY instruction.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_multianewarray(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_VARIABLESBASED
-#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
-#include <typecheck-multianewarray.inc>
-#undef VERIFY_ERROR
-#undef  TYPECHECK_VARIABLESBASED
-
-       return true;
-}
-
-/* typecheck_invalidate_locals *************************************************
-   Invalidate locals that are overwritten by writing to the given local.
-  
-   IN:
-       state............the current state of the verifier
-          index............the index of the local that is written
-          twoword..........true, if a two-word type is written
-
-*******************************************************************************/
-
-static void typecheck_invalidate_locals(verifier_state *state, s4 index, bool twoword)
-{
-       s4 javaindex;
-       s4 t;
-       s4 varindex;
-       jitdata *jd = state->jd;
-       s4 *localmap = jd->local_map;
-       varinfo *vars = jd->var;
-
-       javaindex = jd->reverselocalmap[index];
-
-       /* invalidate locals of two-word type at index javaindex-1 */
-
-       if (javaindex > 0) {
-               localmap += 5 * (javaindex-1);
-               for (t=0; t<5; ++t) {
-                       varindex = *localmap++;
-                       if (varindex >= 0 && IS_2_WORD_TYPE(vars[varindex].type)) {
-                               LOG1("invalidate local %d", varindex);
-                               vars[varindex].type = TYPE_VOID;
-                       }
-               }
-       }
-       else {
-               localmap += 5 * javaindex;
-       }
-
-       /* invalidate locals at index javaindex */
-
-       for (t=0; t<5; ++t) {
-               varindex = *localmap++;
-               if (varindex >= 0) {
-                       LOG1("invalidate local %d", varindex);
-                       vars[varindex].type = TYPE_VOID;
-               }
-       }
-
-       /* if a two-word type is written, invalidate locals at index javaindex+1 */
-
-       if (twoword) {
-               for (t=0; t<5; ++t) {
-                       varindex = *localmap++;
-                       if (varindex >= 0) {
-                               LOG1("invalidate local %d", varindex);
-                               vars[varindex].type = TYPE_VOID;
-                       }
-               }
-       }
-}
-
-
-/* macros used by the generated code ******************************************/
-
-#define EXCEPTION          do { return false; } while (0)
-#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
-
-#define CHECK_LOCAL_TYPE(index, t)                                   \
-    do {                                                             \
-        if (!typevector_checktype(jd->var, (index), (t)))            \
-             VERIFY_ERROR("Local variable type mismatch");           \
-    } while (0)
-
-#define STORE_LOCAL(t, index)                                        \
-    do {                                                             \
-         s4 temp_t = (t);                                            \
-         typecheck_invalidate_locals(state, (index), false);         \
-         typevector_store(jd->var, (index), (temp_t), NULL);         \
-    } while (0)
-
-#define STORE_LOCAL_2_WORD(t, index)                                 \
-    do {                                                             \
-         s4 temp_t = (t);                                            \
-         typecheck_invalidate_locals(state, (index), true);          \
-         typevector_store(jd->var, (index), (temp_t), NULL);         \
-    } while (0)
-
-#define REACH_BLOCK(target)                                          \
-    do {                                                             \
-        if (!typestate_reach(state, (target),                        \
-                             state->bptr->outvars, jd->var,          \
-                             state->bptr->outdepth))                 \
-                return false;                                        \
-    } while (0)
-
-#define REACH(target)   REACH_BLOCK((target).block)
-
-
-/* handle_basic_block **********************************************************
-   Perform bytecode verification of a basic block.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_basic_block(verifier_state *state)
-{
-    int opcode;                                      /* current opcode */
-    int len;                        /* for counting instructions, etc. */
-    bool superblockend;        /* true if no fallthrough to next block */
-       instruction *iptr;                      /* the current instruction */
-    basicblock *tbptr;                   /* temporary for target block */
-    bool maythrow;               /* true if this instruction may throw */
-       s4 i;
-       typecheck_result r;
-       branch_target_t *table;
-       lookup_target_t *lookup;
-       jitdata *jd = state->jd;
-       exception_entry *ex;
-       varinfo constvalue;                               /* for PUT*CONST */
-       constant_FMIref *fieldref;
-
-       LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",state->bptr->nr);
-       LOGFLUSH;
-
-       superblockend = false;
-       state->bptr->flags = BBFINISHED;
-
-       /* prevent compiler warnings */
-
-
-       /* determine the active exception handlers for this block */
-       /* XXX could use a faster algorithm with sorted lists or  */
-       /* something?                                             */
-       len = 0;
-       for (ex = state->jd->exceptiontable; ex ; ex = ex->down) {
-               if ((ex->start->nr <= state->bptr->nr) && (ex->end->nr > state->bptr->nr)) {
-                       LOG1("active handler L%03d", ex->handler->nr);
-                       state->handlers[len++] = ex;
-               }
-       }
-       state->handlers[len] = NULL;
-
-       /* init variable types at the start of this block */
-       typevector_copy_inplace(state->bptr->inlocals, jd->var, state->numlocals);
-
-       DOLOG(show_basicblock(jd, state->bptr, SHOW_STACK));
-       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->invars, 
-                               state->bptr->indepth));
-       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-       LOGNL; LOGFLUSH;
-
-       /* loop over the instructions */
-       len = state->bptr->icount;
-       state->iptr = state->bptr->iinstr;
-       while (--len >= 0)  {
-               TYPECHECK_COUNT(stat_ins);
-
-               iptr = state->iptr;
-
-               DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-               LOGNL; LOGFLUSH;
-               DOLOG(show_icmd(jd, state->iptr, false, SHOW_STACK)); LOGNL; LOGFLUSH;
-
-               opcode = iptr->opc;
-               maythrow = false;
-
-               switch (opcode) {
-
-                       /* include generated code for ICMDs verification */
-
-#define TYPECHECK_VARIABLESBASED
-#define STATE  state
-#define METHOD (state->m)
-#define IPTR   iptr
-#define BPTR   (state->bptr)
-#include <typecheck-variablesbased-gen.inc>
-#undef  STATE
-#undef  METHOD
-#undef  IPTR
-#undef  BPTR
-#undef  TYPECHECK_VARIABLESBASED
-
-                       default:
-                               LOG1("ICMD %d\n", opcode);
-                               TYPECHECK_VERIFYERROR_bool("Missing ICMD code during typecheck");
-               }
-
-               /* reach exception handlers for this instruction */
-
-               if (maythrow) {
-                       TYPECHECK_COUNT(stat_ins_maythrow);
-                       TYPECHECK_MARK(state->stat_maythrow);
-                       LOG("reaching exception handlers");
-                       i = 0;
-                       while (state->handlers[i]) {
-                               TYPECHECK_COUNT(stat_handlers_reached);
-                               if (state->handlers[i]->catchtype.any)
-                                       VAR(state->exinvars)->typeinfo.typeclass = state->handlers[i]->catchtype;
-                               else
-                                       VAR(state->exinvars)->typeinfo.typeclass.cls = class_java_lang_Throwable;
-                               if (!typestate_reach(state,
-                                               state->handlers[i]->handler,
-                                               &(state->exinvars), jd->var, 1))
-                                       return false;
-                               i++;
-                       }
-               }
-
-               LOG("\t\tnext instruction");
-               state->iptr++;
-       } /* while instructions */
-
-       LOG("instructions done");
-       LOGSTR("RESULT=> ");
-       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->outvars,
-                               state->bptr->outdepth));
-       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-       LOGNL; LOGFLUSH;
-
-       /* propagate stack and variables to the following block */
-       if (!superblockend) {
-               LOG("reaching following block");
-               tbptr = state->bptr->next;
-               while (tbptr->flags == BBDELETED) {
-                       tbptr = tbptr->next;
-#ifdef TYPECHECK_DEBUG
-                       /* this must be checked in parse.c */
-                       if ((tbptr->nr) >= state->basicblockcount)
-                               TYPECHECK_VERIFYERROR_bool("Control flow falls off the last block");
-#endif
-               }
-               if (!typestate_reach(state,tbptr,state->bptr->outvars, jd->var,
-                                       state->bptr->outdepth))
-                       return false;
-       }
-
-       /* We may have to restore the types of the instack slots. They
-        * have been saved if an <init> call inside the block has
-        * modified the instack types. (see INVOKESPECIAL) */
-
-       if (state->savedinvars)
-               typestate_restore_invars(state);
-
-       return true;
-}
-
-
-/****************************************************************************/
-/* typecheck()                                                              */
-/* This is the main function of the bytecode verifier. It is called         */
-/* directly after analyse_stack.                                            */
-/*                                                                          */
-/* IN:                                                                      */
-/*    meth.............the method to verify                                 */
-/*    cdata............codegendata for the method                           */
-/*    rdata............registerdata for the method                          */
-/*                                                                          */
-/* RETURN VALUE:                                                            */
-/*     true.............successful verification                             */
-/*     false............an exception has been thrown                        */
-/*                                                                          */
-/****************************************************************************/
-
-#define MAXPARAMS 255
-
-bool typecheck(jitdata *jd)
-{
-       methodinfo     *meth;
-       codegendata    *cd;
-       varinfo        *savedlocals;
-       verifier_state  state;             /* current state of the verifier */
-
-       /* collect statistics */
-
-#ifdef TYPECHECK_STATISTICS
-       int count_iterations = 0;
-       TYPECHECK_COUNT(stat_typechecked);
-       TYPECHECK_COUNT_FREQ(stat_locals,jd->maxlocals,STAT_LOCALS);
-       TYPECHECK_COUNT_FREQ(stat_blocks,cdata->method->basicblockcount/10,STAT_BLOCKS);
-       TYPECHECK_COUNTIF(cdata->method->exceptiontablelength != 0,stat_methods_with_handlers);
-       state.stat_maythrow = false;
-#endif
-
-       /* get required compiler data */
-
-       meth = jd->m;
-       cd   = jd->cd;
-
-       /* some logging on entry */
-
-
-    LOGSTR("\n==============================================================================\n");
-    DOLOG( show_method(jd, SHOW_STACK) );
-    LOGSTR("\n==============================================================================\n");
-    LOGMETHOD("Entering typecheck: ",cd->method);
-
-       /* initialize the verifier state */
-
-       state.m = meth;
-       state.jd = jd;
-       state.cd = cd;
-       state.basicblockcount = jd->basicblockcount;
-       state.basicblocks = jd->basicblocks;
-       state.savedindices = NULL;
-       state.savedinvars = NULL;
-
-       /* check that the basicblock numbers are valid */
-
-#if !defined(NDEBUG)
-       jit_check_basicblock_numbers(jd);
-#endif
-
-       /* check if this method is an instance initializer method */
-
-    state.initmethod = (state.m->name == utf_init);
-
-       /* initialize the basic block flags for the following CFG traversal */
-
-       typecheck_init_flags(&state, BBFINISHED);
-
-    /* number of local variables */
-    
-    /* In <init> methods we use an extra local variable to indicate whether */
-    /* the 'this' reference has been initialized.                           */
-       /*         TYPE_VOID...means 'this' has not been initialized,           */
-       /*         TYPE_INT....means 'this' has been initialized.               */
-
-    state.numlocals = state.jd->localcount;
-       state.validlocals = state.numlocals;
-    if (state.initmethod) 
-               state.numlocals++; /* VERIFIER_EXTRA_LOCALS */
-
-       DOLOG(
-               s4 i;
-               s4 t;
-               LOG("reverselocalmap:");
-               for (i=0; i<state.validlocals; ++i) {
-                       LOG2("    %i => javaindex %i", i, jd->reverselocalmap[i]);
-               });
-
-    /* allocate the buffer of active exception handlers */
-       
-    state.handlers = DMNEW(exception_entry*, state.jd->exceptiontablelength + 1);
-
-       /* save local variables */
-
-       savedlocals = DMNEW(varinfo, state.numlocals);
-       MCOPY(savedlocals, jd->var, varinfo, state.numlocals);
-
-       /* initialized local variables of first block */
-
-       if (!typecheck_init_locals(&state, true))
-               return false;
-
-    /* initialize invars of exception handlers */
-       
-       state.exinvars = state.numlocals;
-       VAR(state.exinvars)->type = TYPE_ADR;
-       typeinfo_init_classinfo(&(VAR(state.exinvars)->typeinfo),
-                                                       class_java_lang_Throwable); /* changed later */
-
-    LOG("Exception handler stacks set.\n");
-
-    /* loop while there are still blocks to be checked */
-    do {
-               TYPECHECK_COUNT(count_iterations);
-
-        state.repeat = false;
-        
-        state.bptr = state.basicblocks;
-
-        for (; state.bptr; state.bptr = state.bptr->next) {
-            LOGSTR1("---- BLOCK %04d, ",state.bptr->nr);
-            LOGSTR1("blockflags: %d\n",state.bptr->flags);
-            LOGFLUSH;
-            
-                   /* verify reached block */  
-            if (state.bptr->flags == BBTYPECHECK_REACHED) {
-                if (!handle_basic_block(&state))
-                                       return false;
-            }
-        } /* for blocks */
-
-        LOGIF(state.repeat,"state.repeat == true");
-    } while (state.repeat);
-
-       /* statistics */
-       
-#ifdef TYPECHECK_STATISTICS
-       LOG1("Typechecker did %4d iterations",count_iterations);
-       TYPECHECK_COUNT_FREQ(stat_iterations,count_iterations,STAT_ITERATIONS);
-       TYPECHECK_COUNTIF(state.jsrencountered,stat_typechecked_jsr);
-       TYPECHECK_COUNTIF(state.stat_maythrow,stat_methods_maythrow);
-#endif
-
-       /* reset the flags of blocks we haven't reached */
-
-       typecheck_reset_flags(&state);
-
-       /* restore locals */
-
-       MCOPY(jd->var, savedlocals, varinfo, state.numlocals);
-
-       /* everything's ok */
-
-    LOGimp("exiting typecheck");
-       return true;
-}
-#endif /* ENABLE_VERIFIER */
-
-/*
- * 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/jit/verify/typecheck.cpp b/src/vm/jit/verify/typecheck.cpp
new file mode 100644 (file)
index 0000000..d63c422
--- /dev/null
@@ -0,0 +1,841 @@
+/* src/vm/jit/verify/typecheck.c - typechecking (part of bytecode verification)
+
+   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.
+
+*/
+
+/*
+
+What's the purpose of the `typechecker`?
+----------------------------------------
+
+The typechecker analyses (the intermediate repr. of) the bytecode of
+each method and ensures that for each instruction the values on the
+stack and in local variables are of the correct type whenever the
+instruction is executed.
+
+type checking is a mandatory part of bytecode verification.
+
+
+How does the typechecker work?
+------------------------------
+
+The JVM stack and the local variables are not statically typed, so the
+typechecker has to *infer* the static types of stack slots and local
+variables at each point of the method. The JVM spec imposes a lot of
+restrictions on the bytecode in order to guarantee that this is always
+possible.
+
+Basically the typechecker solves the data flow equations of the method.
+This is done in the usual way for a forward data flow analysis: Starting
+from the entry point of the method the typechecker follows the CFG and
+records the type of each stack slot and local variable at each point[1].
+When two or more control flow paths merge at a point, the union of the
+types for each slot/variable is taken. The algorithm continues to follow
+all possible paths[2] until the recorded types do not change anymore (ie.
+the equations have been solved).
+
+If the solution has been reached and the resulting types are valid for
+all instructions, then type checking terminates with success, otherwise
+an exception is thrown.
+
+
+Why is this code so damn complicated?
+-------------------------------------
+
+Short answer: The devil's in the details.
+
+While the basic operation of the typechecker is no big deal, there are
+many properties of Java bytecode which make type checking hard. Some of
+them are not even addressed in the JVM spec. Some problems and their
+solutions:
+
+*) Finding a good representation of the union of two reference types is
+difficult because of multiple inheritance of interfaces. 
+
+       Solution: The typeinfo system can represent such "merged" types by a
+       list of proper subclasses of a class. Example:
+
+               typeclass=java.lang.Object merged={ InterfaceA, InterfaceB }
+       
+       represents the result of merging two interface types "InterfaceA"
+       and "InterfaceB".
+
+*) When the code of a method is verified, there may still be unresolved
+references to classes/methods/fields in the code, which we may not force
+to be resolved eagerly. (A similar problem arises because of the special
+checks for protected members.)
+
+       Solution: The typeinfo system knows how to deal with unresolved
+       class references. Whenever a check has to be performed for an
+       unresolved type, the type is annotated with constraints representing
+       the check. Later, when the type is resolved, the constraints are
+       checked. (See the constrain_unresolved_... and the resolve_...
+       methods.)[3]
+
+*) Checks for uninitialized object instances are hard because after the
+invocation of <init> on an uninitialized object *all* slots/variables
+referring to this object (and exactly those slots/variables) must be
+marked as initialized.
+
+       Solution: The JVM spec describes a solution, which has been
+       implemented in this typechecker.
+
+Note that some checks mentioned in the JVM spec are unnecessary[4] and
+not performed by either the reference implementation, or this implementation.
+
+
+--- Footnotes
+
+[1] Actually only the types of slots/variables at the start of each
+basic block are remembered. Within a basic block the algorithm only keeps
+the types of the slots/variables for the "current" instruction which is
+being analysed. 
+
+[2] Actually the algorithm iterates through the basic block list until
+there are no more changes. Theoretically it would be wise to sort the
+basic blocks topologically beforehand, but the number of average/max
+iterations observed is so low, that this was not deemed necessary.
+
+[3] This is similar to a method proposed by: Alessandro Coglio et al., A
+Formal Specification of Java Class Loading, Technical Report, Kestrel
+Institute April 2000, revised July 2000 
+http://www.kestrel.edu/home/people/coglio/loading.pdf
+An important difference is that Coglio's subtype constraints are checked
+after loading, while our constraints are checked when the field/method
+is accessed for the first time, so we can guarantee lexically correct
+error reporting.
+
+[4] Alessandro Coglio
+    Improving the official specification of Java bytecode verification
+    Proceedings of the 3rd ECOOP Workshop on Formal Techniques for Java Programs
+    June 2001
+    citeseer.ist.psu.edu/article/coglio03improving.html
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "vm/types.h"
+
+#ifdef ENABLE_VERIFIER
+
+#include "mm/memory.h"
+
+#include "native/native.hpp"
+
+#include "toolbox/logging.h"
+
+#include "vm/access.hpp"
+#include "vm/array.hpp"
+#include "vm/jit/builtin.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/globals.hpp"
+#include "vm/loader.hpp"
+#include "vm/options.h"
+#include "vm/primitive.hpp"
+#include "vm/resolve.hpp"
+
+#include "vm/jit/jit.hpp"
+#include "vm/jit/parse.hpp"
+#include "vm/jit/show.hpp"
+
+#include "vm/jit/verify/typecheck-common.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/****************************************************************************/
+/* MACROS FOR VARIABLE TYPE CHECKING                                        */
+/****************************************************************************/
+
+#define TYPECHECK_CHECK_TYPE(i,tp,msg)                               \
+    do {                                                             \
+        if (VAR(i)->type != (tp)) {                                  \
+            exceptions_throw_verifyerror(state->m, (msg));           \
+            return false;                                            \
+        }                                                            \
+    } while (0)
+
+#define TYPECHECK_INT(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_INT,"Expected to find integer value")
+#define TYPECHECK_LNG(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_LNG,"Expected to find long value")
+#define TYPECHECK_FLT(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_FLT,"Expected to find float value")
+#define TYPECHECK_DBL(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_DBL,"Expected to find double value")
+#define TYPECHECK_ADR(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_ADR,"Expected to find object value")
+
+#define TYPECHECK_INT_OP(o)  TYPECHECK_INT((o).varindex)
+#define TYPECHECK_LNG_OP(o)  TYPECHECK_LNG((o).varindex)
+#define TYPECHECK_FLT_OP(o)  TYPECHECK_FLT((o).varindex)
+#define TYPECHECK_DBL_OP(o)  TYPECHECK_DBL((o).varindex)
+#define TYPECHECK_ADR_OP(o)  TYPECHECK_ADR((o).varindex)
+
+
+/* typestate_save_invars *******************************************************
+   Save the invars of the current basic block in the space reserved by
+   parse.
+
+   This function must be called before an instruction modifies a variable
+   that is an invar of the current block. In such cases the invars of the
+   block must be saved, and restored at the end of the analysis of this
+   basic block, so that the invars again reflect the *input* to this basic
+   block (and do not randomly contain types that appear within the block).
+
+   IN:
+       state............current state of the verifier
+
+*******************************************************************************/
+
+static void
+typestate_save_invars(verifier_state *state)
+{
+       s4 i, index;
+       s4 *pindex;
+       
+       LOG("saving invars");
+
+       if (!state->savedindices) {
+               LOG("allocating savedindices buffer");
+               pindex = (s4*) DumpMemory::allocate(sizeof(s4) * state->m->maxstack);
+               state->savedindices = pindex;
+               index = state->numlocals + VERIFIER_EXTRA_VARS;
+               for (i=0; i<state->m->maxstack; ++i)
+                       *pindex++ = index++;
+       }
+
+       /* save types */
+
+       typecheck_copy_types(state, state->bptr->invars, state->savedindices, 
+                       state->bptr->indepth);
+
+       /* set the invars of the block to the saved variables */
+       /* and remember the original invars                   */
+
+       state->savedinvars = state->bptr->invars;
+       state->bptr->invars = state->savedindices;
+}
+
+
+/* typestate_restore_invars  ***************************************************
+   Restore the invars of the current basic block that have been previously
+   saved by `typestate_save_invars`.
+
+   IN:
+       state............current state of the verifier
+
+*******************************************************************************/
+
+static void
+typestate_restore_invars(verifier_state *state)
+{
+       TYPECHECK_COUNT(stat_savedstack);
+       LOG("restoring saved invars");
+
+       /* restore the invars pointer */
+
+       state->bptr->invars = state->savedinvars;
+
+       /* copy the types back */
+
+       typecheck_copy_types(state, state->savedindices, state->bptr->invars,
+                       state->bptr->indepth);
+
+       /* mark that there are no saved invars currently */
+
+       state->savedinvars = NULL;
+}
+
+
+/* handle_fieldaccess **********************************************************
+   Verify an ICMD_{GET,PUT}{STATIC,FIELD}(CONST)?
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_fieldaccess(verifier_state *state,
+                                  varinfo *instance,
+                                  varinfo *value)
+{
+       jitdata *jd;
+
+       jd = state->jd;
+
+#define TYPECHECK_VARIABLESBASED
+#define EXCEPTION  do { return false; } while (0)
+#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
+#include <typecheck-fields.inc>
+#undef  EXCEPTION
+#undef  VERIFY_ERROR
+#undef  TYPECHECK_VARIABLESBASED
+
+       return true;
+}
+
+
+/* handle_invocation ***********************************************************
+   Verify an ICMD_INVOKE* instruction.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_invocation(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_VARIABLESBASED
+#define OP1   VAR(state->iptr->sx.s23.s2.args[0])
+#include <typecheck-invoke.inc>
+#undef  OP1
+#undef  TYPECHECK_VARIABLESBASED
+
+       return true;
+}
+
+
+/* handle_builtin **************************************************************
+   Verify the call of a builtin method.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_builtin(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_VARIABLESBASED
+#define OP1   state->iptr->sx.s23.s2.args[0]
+#include <typecheck-builtins.inc>
+#undef  OP1
+#undef  TYPECHECK_VARIABLESBASED
+
+       return true;
+}
+
+/* handle_multianewarray *******************************************************
+   Verify a MULTIANEWARRAY instruction.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_multianewarray(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_VARIABLESBASED
+#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
+#include <typecheck-multianewarray.inc>
+#undef VERIFY_ERROR
+#undef  TYPECHECK_VARIABLESBASED
+
+       return true;
+}
+
+/* typecheck_invalidate_locals *************************************************
+   Invalidate locals that are overwritten by writing to the given local.
+  
+   IN:
+       state............the current state of the verifier
+          index............the index of the local that is written
+          twoword..........true, if a two-word type is written
+
+*******************************************************************************/
+
+static void typecheck_invalidate_locals(verifier_state *state, s4 index, bool twoword)
+{
+       s4 javaindex;
+       s4 t;
+       s4 varindex;
+       jitdata *jd = state->jd;
+       s4 *localmap = jd->local_map;
+       varinfo *vars = jd->var;
+
+       javaindex = jd->reverselocalmap[index];
+
+       /* invalidate locals of two-word type at index javaindex-1 */
+
+       if (javaindex > 0) {
+               localmap += 5 * (javaindex-1);
+               for (t=0; t<5; ++t) {
+                       varindex = *localmap++;
+                       if (varindex >= 0 && IS_2_WORD_TYPE(vars[varindex].type)) {
+                               LOG1("invalidate local %d", varindex);
+                               vars[varindex].type = TYPE_VOID;
+                       }
+               }
+       }
+       else {
+               localmap += 5 * javaindex;
+       }
+
+       /* invalidate locals at index javaindex */
+
+       for (t=0; t<5; ++t) {
+               varindex = *localmap++;
+               if (varindex >= 0) {
+                       LOG1("invalidate local %d", varindex);
+                       vars[varindex].type = TYPE_VOID;
+               }
+       }
+
+       /* if a two-word type is written, invalidate locals at index javaindex+1 */
+
+       if (twoword) {
+               for (t=0; t<5; ++t) {
+                       varindex = *localmap++;
+                       if (varindex >= 0) {
+                               LOG1("invalidate local %d", varindex);
+                               vars[varindex].type = TYPE_VOID;
+                       }
+               }
+       }
+}
+
+
+/* macros used by the generated code ******************************************/
+
+#define EXCEPTION          do { return false; } while (0)
+#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
+
+#define CHECK_LOCAL_TYPE(index, t)                                   \
+    do {                                                             \
+        if (!typevector_checktype(jd->var, (index), (t)))            \
+             VERIFY_ERROR("Local variable type mismatch");           \
+    } while (0)
+
+#define STORE_LOCAL(t, index)                                        \
+    do {                                                             \
+         s4 temp_t = (t);                                            \
+         typecheck_invalidate_locals(state, (index), false);         \
+         typevector_store(jd->var, (index), (temp_t), NULL);         \
+    } while (0)
+
+#define STORE_LOCAL_2_WORD(t, index)                                 \
+    do {                                                             \
+         s4 temp_t = (t);                                            \
+         typecheck_invalidate_locals(state, (index), true);          \
+         typevector_store(jd->var, (index), (temp_t), NULL);         \
+    } while (0)
+
+#define REACH_BLOCK(target)                                          \
+    do {                                                             \
+        if (!typestate_reach(state, (target),                        \
+                             state->bptr->outvars, jd->var,          \
+                             state->bptr->outdepth))                 \
+                return false;                                        \
+    } while (0)
+
+#define REACH(target)   REACH_BLOCK((target).block)
+
+
+/* handle_basic_block **********************************************************
+   Perform bytecode verification of a basic block.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_basic_block(verifier_state *state)
+{
+    int opcode;                                      /* current opcode */
+    int len;                        /* for counting instructions, etc. */
+    bool superblockend;        /* true if no fallthrough to next block */
+       instruction *iptr;                      /* the current instruction */
+    basicblock *tbptr;                   /* temporary for target block */
+    bool maythrow;               /* true if this instruction may throw */
+       s4 i;
+       typecheck_result r;
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       jitdata *jd = state->jd;
+       exception_entry *ex;
+       varinfo constvalue;                               /* for PUT*CONST */
+       constant_FMIref *fieldref;
+
+       LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",state->bptr->nr);
+       LOGFLUSH;
+
+       superblockend = false;
+       state->bptr->flags = BBFINISHED;
+
+       /* prevent compiler warnings */
+
+
+       /* determine the active exception handlers for this block */
+       /* XXX could use a faster algorithm with sorted lists or  */
+       /* something?                                             */
+       len = 0;
+       for (ex = state->jd->exceptiontable; ex ; ex = ex->down) {
+               if ((ex->start->nr <= state->bptr->nr) && (ex->end->nr > state->bptr->nr)) {
+                       LOG1("active handler L%03d", ex->handler->nr);
+                       state->handlers[len++] = ex;
+               }
+       }
+       state->handlers[len] = NULL;
+
+       /* init variable types at the start of this block */
+       typevector_copy_inplace(state->bptr->inlocals, jd->var, state->numlocals);
+
+       DOLOG(show_basicblock(jd, state->bptr, SHOW_STACK));
+       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->invars, 
+                               state->bptr->indepth));
+       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+       LOGNL; LOGFLUSH;
+
+       /* loop over the instructions */
+       len = state->bptr->icount;
+       state->iptr = state->bptr->iinstr;
+       while (--len >= 0)  {
+               TYPECHECK_COUNT(stat_ins);
+
+               iptr = state->iptr;
+
+               DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+               LOGNL; LOGFLUSH;
+               DOLOG(show_icmd(jd, state->iptr, false, SHOW_STACK)); LOGNL; LOGFLUSH;
+
+               opcode = iptr->opc;
+               maythrow = false;
+
+               switch (opcode) {
+
+                       /* include generated code for ICMDs verification */
+
+#define TYPECHECK_VARIABLESBASED
+#define STATE  state
+#define METHOD (state->m)
+#define IPTR   iptr
+#define BPTR   (state->bptr)
+#include <typecheck-variablesbased-gen.inc>
+#undef  STATE
+#undef  METHOD
+#undef  IPTR
+#undef  BPTR
+#undef  TYPECHECK_VARIABLESBASED
+
+                       default:
+                               LOG1("ICMD %d\n", opcode);
+                               TYPECHECK_VERIFYERROR_bool("Missing ICMD code during typecheck");
+               }
+
+               /* reach exception handlers for this instruction */
+
+               if (maythrow) {
+                       TYPECHECK_COUNT(stat_ins_maythrow);
+                       TYPECHECK_MARK(state->stat_maythrow);
+                       LOG("reaching exception handlers");
+                       i = 0;
+                       while (state->handlers[i]) {
+                               TYPECHECK_COUNT(stat_handlers_reached);
+                               if (state->handlers[i]->catchtype.any)
+                                       VAR(state->exinvars)->typeinfo.typeclass = state->handlers[i]->catchtype;
+                               else
+                                       VAR(state->exinvars)->typeinfo.typeclass.cls = class_java_lang_Throwable;
+                               if (!typestate_reach(state,
+                                               state->handlers[i]->handler,
+                                               &(state->exinvars), jd->var, 1))
+                                       return false;
+                               i++;
+                       }
+               }
+
+               LOG("\t\tnext instruction");
+               state->iptr++;
+       } /* while instructions */
+
+       LOG("instructions done");
+       LOGSTR("RESULT=> ");
+       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->outvars,
+                               state->bptr->outdepth));
+       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+       LOGNL; LOGFLUSH;
+
+       /* propagate stack and variables to the following block */
+       if (!superblockend) {
+               LOG("reaching following block");
+               tbptr = state->bptr->next;
+               while (tbptr->flags == BBDELETED) {
+                       tbptr = tbptr->next;
+#ifdef TYPECHECK_DEBUG
+                       /* this must be checked in parse.c */
+                       if ((tbptr->nr) >= state->basicblockcount)
+                               TYPECHECK_VERIFYERROR_bool("Control flow falls off the last block");
+#endif
+               }
+               if (!typestate_reach(state,tbptr,state->bptr->outvars, jd->var,
+                                       state->bptr->outdepth))
+                       return false;
+       }
+
+       /* We may have to restore the types of the instack slots. They
+        * have been saved if an <init> call inside the block has
+        * modified the instack types. (see INVOKESPECIAL) */
+
+       if (state->savedinvars)
+               typestate_restore_invars(state);
+
+       return true;
+}
+
+
+/****************************************************************************/
+/* typecheck()                                                              */
+/* This is the main function of the bytecode verifier. It is called         */
+/* directly after analyse_stack.                                            */
+/*                                                                          */
+/* IN:                                                                      */
+/*    meth.............the method to verify                                 */
+/*    cdata............codegendata for the method                           */
+/*    rdata............registerdata for the method                          */
+/*                                                                          */
+/* RETURN VALUE:                                                            */
+/*     true.............successful verification                             */
+/*     false............an exception has been thrown                        */
+/*                                                                          */
+/****************************************************************************/
+
+#define MAXPARAMS 255
+
+bool typecheck(jitdata *jd)
+{
+       methodinfo     *meth;
+       codegendata    *cd;
+       varinfo        *savedlocals;
+       verifier_state  state;             /* current state of the verifier */
+
+       /* collect statistics */
+
+#ifdef TYPECHECK_STATISTICS
+       int count_iterations = 0;
+       TYPECHECK_COUNT(stat_typechecked);
+       TYPECHECK_COUNT_FREQ(stat_locals,jd->maxlocals,STAT_LOCALS);
+       TYPECHECK_COUNT_FREQ(stat_blocks,cdata->method->basicblockcount/10,STAT_BLOCKS);
+       TYPECHECK_COUNTIF(cdata->method->exceptiontablelength != 0,stat_methods_with_handlers);
+       state.stat_maythrow = false;
+#endif
+
+       /* get required compiler data */
+
+       meth = jd->m;
+       cd   = jd->cd;
+
+       /* some logging on entry */
+
+
+    LOGSTR("\n==============================================================================\n");
+    DOLOG( show_method(jd, SHOW_STACK) );
+    LOGSTR("\n==============================================================================\n");
+    LOGMETHOD("Entering typecheck: ",cd->method);
+
+       /* initialize the verifier state */
+
+       state.m = meth;
+       state.jd = jd;
+       state.cd = cd;
+       state.basicblockcount = jd->basicblockcount;
+       state.basicblocks = jd->basicblocks;
+       state.savedindices = NULL;
+       state.savedinvars = NULL;
+
+       /* check that the basicblock numbers are valid */
+
+#if !defined(NDEBUG)
+       jit_check_basicblock_numbers(jd);
+#endif
+
+       /* check if this method is an instance initializer method */
+
+    state.initmethod = (state.m->name == utf_init);
+
+       /* initialize the basic block flags for the following CFG traversal */
+
+       typecheck_init_flags(&state, BBFINISHED);
+
+    /* number of local variables */
+    
+    /* In <init> methods we use an extra local variable to indicate whether */
+    /* the 'this' reference has been initialized.                           */
+       /*         TYPE_VOID...means 'this' has not been initialized,           */
+       /*         TYPE_INT....means 'this' has been initialized.               */
+
+    state.numlocals = state.jd->localcount;
+       state.validlocals = state.numlocals;
+    if (state.initmethod) 
+               state.numlocals++; /* VERIFIER_EXTRA_LOCALS */
+
+       DOLOG(
+               s4 i;
+               s4 t;
+               LOG("reverselocalmap:");
+               for (i=0; i<state.validlocals; ++i) {
+                       LOG2("    %i => javaindex %i", i, jd->reverselocalmap[i]);
+               });
+
+    /* allocate the buffer of active exception handlers */
+       
+    state.handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (state.jd->exceptiontablelength + 1));
+
+       /* save local variables */
+
+       savedlocals = (varinfo*) DumpMemory::allocate(sizeof(varinfo) * state.numlocals);
+       MCOPY(savedlocals, jd->var, varinfo, state.numlocals);
+
+       /* initialized local variables of first block */
+
+       if (!typecheck_init_locals(&state, true))
+               return false;
+
+    /* initialize invars of exception handlers */
+       
+       state.exinvars = state.numlocals;
+       VAR(state.exinvars)->type = TYPE_ADR;
+       typeinfo_init_classinfo(&(VAR(state.exinvars)->typeinfo),
+                                                       class_java_lang_Throwable); /* changed later */
+
+    LOG("Exception handler stacks set.\n");
+
+    /* loop while there are still blocks to be checked */
+    do {
+               TYPECHECK_COUNT(count_iterations);
+
+        state.repeat = false;
+        
+        state.bptr = state.basicblocks;
+
+        for (; state.bptr; state.bptr = state.bptr->next) {
+            LOGSTR1("---- BLOCK %04d, ",state.bptr->nr);
+            LOGSTR1("blockflags: %d\n",state.bptr->flags);
+            LOGFLUSH;
+            
+                   /* verify reached block */  
+            if (state.bptr->flags == BBTYPECHECK_REACHED) {
+                if (!handle_basic_block(&state))
+                                       return false;
+            }
+        } /* for blocks */
+
+        LOGIF(state.repeat,"state.repeat == true");
+    } while (state.repeat);
+
+       /* statistics */
+       
+#ifdef TYPECHECK_STATISTICS
+       LOG1("Typechecker did %4d iterations",count_iterations);
+       TYPECHECK_COUNT_FREQ(stat_iterations,count_iterations,STAT_ITERATIONS);
+       TYPECHECK_COUNTIF(state.jsrencountered,stat_typechecked_jsr);
+       TYPECHECK_COUNTIF(state.stat_maythrow,stat_methods_maythrow);
+#endif
+
+       /* reset the flags of blocks we haven't reached */
+
+       typecheck_reset_flags(&state);
+
+       /* restore locals */
+
+       MCOPY(jd->var, savedlocals, varinfo, state.numlocals);
+
+       /* everything's ok */
+
+    LOGimp("exiting typecheck");
+       return true;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* ENABLE_VERIFIER */
+
+/*
+ * 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/jit/verify/typecheck.h b/src/vm/jit/verify/typecheck.h
deleted file mode 100644 (file)
index dac58ca..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* src/vm/jit/verify/typecheck.h - type checking header
-
-   Copyright (C) 1996-2005, 2006, 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 _TYPECHECK_H
-#define _TYPECHECK_H
-
-#include "config.h"
-
-#include "vm/global.h"
-#include "vm/jit/jit.hpp"
-
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(ENABLE_VERIFIER)
-bool typecheck(jitdata *jd);
-bool typecheck_stackbased(jitdata *jd);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _TYPECHECK_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/jit/verify/typecheck.hpp b/src/vm/jit/verify/typecheck.hpp
new file mode 100644 (file)
index 0000000..8e0305c
--- /dev/null
@@ -0,0 +1,64 @@
+/* src/vm/jit/verify/typecheck.h - type checking header
+
+   Copyright (C) 1996-2005, 2006, 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 _TYPECHECK_H
+#define _TYPECHECK_H
+
+#include "config.h"
+
+#include "vm/global.h"
+#include "vm/jit/jit.hpp"
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(ENABLE_VERIFIER)
+bool typecheck(jitdata *jd);
+bool typecheck_stackbased(jitdata *jd);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TYPECHECK_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/jit/verify/typeinfo.c b/src/vm/jit/verify/typeinfo.c
deleted file mode 100644 (file)
index 1da1810..0000000
+++ /dev/null
@@ -1,2565 +0,0 @@
-/* src/vm/jit/verify/typeinfo.c - type system used by the type checker
-
-   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 <string.h>
-
-#include "mm/memory.h"
-
-#include "toolbox/logging.h"
-
-#include "vm/array.hpp"
-#include "vm/class.hpp"
-#include "vm/descriptor.h"
-#include "vm/exceptions.hpp"
-#include "vm/globals.hpp"
-#include "vm/loader.hpp"
-#include "vm/primitive.hpp"
-#include "vm/resolve.hpp"
-
-#include "vm/jit/jit.hpp"
-#include "vm/jit/verify/typeinfo.h"
-
-
-/* check if a linked class is an array class. Only use for linked classes! */
-#define CLASSINFO_IS_ARRAY(clsinfo)  ((clsinfo)->vftbl->arraydesc != NULL)
-
-/* check if a linked class implements the interface with the given index */
-#define CLASSINFO_IMPLEMENTS_INTERFACE(cls,index)                   \
-    ( ((index) < (cls)->vftbl->interfacetablelength)            \
-      && ( (cls)->vftbl->interfacetable[-(index)] != NULL ) )
-
-/******************************************************************************/
-/* DEBUG HELPERS                                                              */
-/******************************************************************************/
-
-#ifdef TYPEINFO_DEBUG
-#define TYPEINFO_ASSERT(cond)  assert(cond)
-#else
-#define TYPEINFO_ASSERT(cond)
-#endif
-
-/**********************************************************************/
-/* TYPEVECTOR FUNCTIONS                                               */
-/**********************************************************************/
-
-#if defined(ENABLE_VERIFIER)
-
-/* typevector_copy *************************************************************
-   Return a copy of the given typevector.
-  
-   IN:
-          src..............typevector set to copy, must be != NULL
-          size.............number of elements per typevector
-
-   RETURN VALUE:
-       a pointer to the new typevector set
-
-*******************************************************************************/
-
-varinfo *
-typevector_copy(varinfo *src, int size)
-{
-       varinfo *dst;
-       
-       TYPEINFO_ASSERT(src);
-       
-       dst = DNEW_TYPEVECTOR(size);
-       memcpy(dst,src,TYPEVECTOR_SIZE(size));
-
-       return dst;
-}
-
-/* typevector_copy_inplace *****************************************************
-   Copy a typevector to a given destination.
-
-   IN:
-          src..............typevector to copy, must be != NULL
-          dst..............destination to write the copy to
-          size.............number of elements per typevector
-
-*******************************************************************************/
-
-void
-typevector_copy_inplace(varinfo *src,varinfo *dst,int size)
-{
-       memcpy(dst,src,TYPEVECTOR_SIZE(size));
-}
-
-/* typevector_checktype ********************************************************
-   Check if the typevector contains a given type at a given index.
-  
-   IN:
-          vec..............typevector set, must be != NULL
-          index............index of component to check
-          type.............TYPE_* constant to check against
-
-   RETURN VALUE:
-       true if the typevector contains TYPE at INDEX,
-          false otherwise
-
-*******************************************************************************/
-
-bool
-typevector_checktype(varinfo *vec,int index,int type)
-{
-       TYPEINFO_ASSERT(vec);
-
-       return vec[index].type == type;
-}
-
-/* typevector_checkreference ***************************************************
-   Check if the typevector contains a reference at a given index.
-  
-   IN:
-          vec..............typevector, must be != NULL
-          index............index of component to check
-
-   RETURN VALUE:
-       true if the typevector contains a reference at INDEX,
-          false otherwise
-
-*******************************************************************************/
-
-bool
-typevector_checkreference(varinfo *vec, int index)
-{
-       TYPEINFO_ASSERT(vec);
-       return TYPEDESC_IS_REFERENCE(vec[index]);
-}
-
-/* typevectorset_checkretaddr **************************************************
-   Check if the typevectors contains a returnAddress at a given index.
-  
-   IN:
-          vec..............typevector, must be != NULL
-          index............index of component to check
-
-   RETURN VALUE:
-       true if the typevector contains a returnAddress at INDEX,
-          false otherwise
-
-*******************************************************************************/
-
-bool
-typevector_checkretaddr(varinfo *vec,int index)
-{
-       TYPEINFO_ASSERT(vec);
-       return TYPEDESC_IS_RETURNADDRESS(vec[index]);
-}
-
-/* typevector_store ************************************************************
-   Store a type at a given index in the typevector.
-  
-   IN:
-          vec..............typevector set, must be != NULL
-          index............index of component to set
-          type.............TYPE_* constant of type to set
-          info.............typeinfo of type to set, may be NULL, 
-                           if TYPE != TYPE_ADR
-
-*******************************************************************************/
-
-void
-typevector_store(varinfo *vec,int index,int type,typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(vec);
-
-       vec[index].type = type;
-       if (info)
-               TYPEINFO_COPY(*info,vec[index].typeinfo);
-}
-
-/* typevector_store_retaddr ****************************************************
-   Store a returnAddress type at a given index in the typevector.
-  
-   IN:
-          vec..............typevector set, must be != NULL
-          index............index of component to set
-          info.............typeinfo of the returnAddress.
-
-*******************************************************************************/
-
-void
-typevector_store_retaddr(varinfo *vec,int index,typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(vec);
-       TYPEINFO_ASSERT(TYPEINFO_IS_PRIMITIVE(*info));
-       
-       vec[index].type = TYPE_ADR;
-       TYPEINFO_INIT_RETURNADDRESS(vec[index].typeinfo,
-                       TYPEINFO_RETURNADDRESS(*info));
-}
-
-/* typevector_init_object ******************************************************
-   Replace all uninitialized object types in the typevector set which were 
-   created by the given instruction by initialized object types.
-  
-   IN:
-          set..............typevector set
-          ins..............instruction which created the uninitialized object type
-          initclass........class of the initialized object type to set
-          size.............number of elements per typevector
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-   XXX maybe we should do the lazy resolving before calling this function
-
-*******************************************************************************/
-
-bool
-typevector_init_object(varinfo *set,void *ins,
-                                          classref_or_classinfo initclass,
-                                          int size)
-{
-       int i;
-
-       for (i=0; i<size; ++i) {
-               if (set[i].type == TYPE_ADR
-                       && TYPEINFO_IS_NEWOBJECT(set[i].typeinfo)
-                       && TYPEINFO_NEWOBJECT_INSTRUCTION(set[i].typeinfo) == ins)
-               {
-                       if (!typeinfo_init_class(&(set[i].typeinfo),initclass))
-                               return false;
-               }
-       }
-       return true;
-}
-
-/* typevector_merge ************************************************************
-   Merge a typevector with another one.
-   The given typevectors must have the same number of components.
-  
-   IN:
-       m................method for exception messages
-          dst..............the first typevector
-          y................the second typevector
-          size.............number of elements per typevector
-
-   OUT:
-       *dst.............the resulting typevector
-
-   RETURN VALUE:
-       typecheck_TRUE...dst has been modified
-          typecheck_FALSE..dst has not been modified
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result
-typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size)
-{
-       bool changed = false;
-       typecheck_result r;
-       
-       varinfo *a = dst;
-       varinfo *b = y;
-       while (size--) {
-               if (a->type != TYPE_VOID && a->type != b->type) {
-                       a->type = TYPE_VOID;
-                       changed = true;
-               }
-               else if (a->type == TYPE_ADR) {
-                       if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) {
-                               /* 'a' is a returnAddress */
-                               if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo)
-                                       || (TYPEINFO_RETURNADDRESS(a->typeinfo)
-                                               != TYPEINFO_RETURNADDRESS(b->typeinfo)))
-                               {
-                                       a->type = TYPE_VOID;
-                                       changed = true;
-                               }
-                       }
-                       else {
-                               /* 'a' is a reference */
-                               if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) {
-                                       a->type = TYPE_VOID;
-                                       changed = true;
-                               }
-                               else {
-                                       /* two reference types are merged. There cannot be */
-                                       /* a merge error. In the worst case we get j.l.O.  */
-                                       r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo));
-                                       if (r == typecheck_FAIL)
-                                               return r;
-                                       changed |= r;
-                               }
-                       }
-               }
-               a++;
-               b++;
-       }
-       return changed;
-}
-
-/**********************************************************************/
-/* READ-ONLY FUNCTIONS                                                */
-/* The following functions don't change typeinfo data.                */
-/**********************************************************************/
-
-/* typeinfo_is_array ***********************************************************
-   Check whether a typeinfo describes an array type.
-   
-   IN:
-          info.............the typeinfo, must be != NULL
-
-   RETURN VALUE:
-       true if INFO describes an array type.
-
-*******************************************************************************/
-
-bool
-typeinfo_is_array(typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(info);
-    return TYPEINFO_IS_ARRAY(*info);
-}
-
-/* typeinfo_is_primitive_array *************************************************
-   Check whether a typeinfo describes a primitive array type.
-   
-   IN:
-          info.............the typeinfo, must be != NULL
-
-   RETURN VALUE:
-       true if INFO describes an array of a primitive type.
-
-*******************************************************************************/
-
-bool
-typeinfo_is_primitive_array(typeinfo_t *info,int arraytype)
-{
-       TYPEINFO_ASSERT(info);
-    return TYPEINFO_IS_PRIMITIVE_ARRAY(*info,arraytype);
-}
-
-/* typeinfo_is_array_of_refs ***************************************************
-   Check whether a typeinfo describes an array of references type.
-   
-   IN:
-          info.............the typeinfo, must be != NULL
-
-   RETURN VALUE:
-       true if INFO describes an array of a refrence type.
-
-*******************************************************************************/
-
-bool
-typeinfo_is_array_of_refs(typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(info);
-    return TYPEINFO_IS_ARRAY_OF_REFS(*info);
-}
-
-/* interface_extends_interface *************************************************
-   Check if a resolved interface extends a given resolved interface.
-   
-   IN:
-          cls..............the interface, must be linked
-          interf...........the interface to check against
-
-   RETURN VALUE:
-       true.............CLS extends INTERF
-          false............CLS does not extend INTERF
-
-*******************************************************************************/
-
-static bool
-interface_extends_interface(classinfo *cls,classinfo *interf)
-{
-    int i;
-    
-       TYPEINFO_ASSERT(cls);
-       TYPEINFO_ASSERT(interf);
-       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
-       TYPEINFO_ASSERT((cls->flags & ACC_INTERFACE) != 0);
-       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
-
-    /* first check direct superinterfaces */
-    for (i=0; i<cls->interfacescount; ++i) {
-        if (cls->interfaces[i] == interf)
-            return true;
-    }
-    
-    /* check indirect superinterfaces */
-    for (i=0; i<cls->interfacescount; ++i) {
-        if (interface_extends_interface(cls->interfaces[i],interf))
-            return true;
-    }
-    
-    return false;
-}
-
-/* classinfo_implements_interface **********************************************
-   Check if a resolved class implements a given resolved interface.
-   
-   IN:
-          cls..............the class
-          interf...........the interface
-
-   RETURN VALUE:
-       typecheck_TRUE...CLS implements INTERF
-          typecheck_FALSE..CLS does not implement INTERF
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-static typecheck_result
-classinfo_implements_interface(classinfo *cls,classinfo *interf)
-{
-       TYPEINFO_ASSERT(cls);
-       TYPEINFO_ASSERT(interf);
-       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
-
-       if (!(cls->state & CLASS_LINKED))
-               if (!link_class(cls))
-                       return typecheck_FAIL;
-
-    if (cls->flags & ACC_INTERFACE) {
-        /* cls is an interface */
-        if (cls == interf)
-            return typecheck_TRUE;
-
-        /* check superinterfaces */
-        return interface_extends_interface(cls,interf);
-    }
-
-       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
-    return CLASSINFO_IMPLEMENTS_INTERFACE(cls,interf->index);
-}
-
-/* mergedlist_implements_interface *********************************************
-   Check if all the classes in a given merged list implement a given resolved
-   interface.
-   
-   IN:
-          merged...........the list of merged class types
-          interf...........the interface to check against
-
-   RETURN VALUE:
-       typecheck_TRUE...all classes implement INTERF
-          typecheck_FALSE..there is at least one class that does not implement
-                           INTERF
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-static typecheck_result
-mergedlist_implements_interface(typeinfo_mergedlist_t *merged,
-                                classinfo *interf)
-{
-    int i;
-    classref_or_classinfo *mlist;
-       typecheck_result r;
-    
-       TYPEINFO_ASSERT(interf);
-       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
-
-    /* Check if there is an non-empty mergedlist. */
-    if (!merged)
-        return typecheck_FALSE;
-
-    /* If all classinfos in the (non-empty) merged array implement the
-     * interface return true, otherwise false.
-     */
-    mlist = merged->list;
-    i = merged->count;
-    while (i--) {
-               if (IS_CLASSREF(*mlist)) {
-                       return typecheck_MAYBE;
-               }
-        r = classinfo_implements_interface((mlist++)->cls,interf);
-        if (r != typecheck_TRUE)
-                       return r;
-    }
-    return typecheck_TRUE;
-}
-
-/* merged_implements_interface *************************************************
-   Check if a possible merged type implements a given resolved interface
-   interface.
-   
-   IN:
-       typeclass........(common) class of the (merged) type
-          merged...........the list of merged class types
-          interf...........the interface to check against
-
-   RETURN VALUE:
-       typecheck_TRUE...the type implement INTERF
-          typecheck_FALSE..the type does not implement INTERF
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-static typecheck_result
-merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist_t *merged,
-                            classinfo *interf)
-{
-       typecheck_result r;
-       
-    /* primitive types don't support interfaces. */
-    if (!typeclass)
-        return typecheck_FALSE;
-
-    /* the null type can be cast to any interface type. */
-    if (typeclass == pseudo_class_Null)
-        return typecheck_TRUE;
-
-    /* check if typeclass implements the interface. */
-    r = classinfo_implements_interface(typeclass,interf);
-       if (r != typecheck_FALSE)
-        return r;
-
-    /* check the mergedlist */
-       if (!merged)
-               return typecheck_FALSE;
-    return mergedlist_implements_interface(merged,interf);
-}
-
-/* merged_is_subclass **********************************************************
-   Check if a possible merged type is a subclass of a given class.
-   A merged type is a subclass of a class C if all types in the merged list
-   are subclasses of C. A sufficient condition for this is that the
-   common type of the merged type is a subclass of C.
-
-   IN:
-       typeclass........(common) class of the (merged) type
-                           MUST be a loaded and linked class
-          merged...........the list of merged class types
-          cls..............the class to theck against
-
-   RETURN VALUE:
-       typecheck_TRUE...the type is a subclass of CLS
-          typecheck_FALSE..the type is not a subclass of CLS
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-static typecheck_result
-merged_is_subclass(classinfo *typeclass,typeinfo_mergedlist_t *merged,
-               classinfo *cls)
-{
-    int i;
-    classref_or_classinfo *mlist;
-
-       TYPEINFO_ASSERT(cls);
-       
-    /* primitive types aren't subclasses of anything. */
-    if (!typeclass)
-        return typecheck_FALSE;
-
-    /* the null type can be cast to any reference type. */
-    if (typeclass == pseudo_class_Null)
-        return typecheck_TRUE;
-
-       TYPEINFO_ASSERT(typeclass->state & CLASS_LOADED);
-       TYPEINFO_ASSERT(typeclass->state & CLASS_LINKED);
-
-    /* check if the common typeclass is a subclass of CLS. */
-       if (class_issubclass(typeclass,cls))
-               return typecheck_TRUE;
-       
-    /* check the mergedlist */
-       if (!merged)
-               return typecheck_FALSE;
-    /* If all classinfos in the (non-empty) merged list are subclasses
-        * of CLS, return true, otherwise false.
-        * If there is at least one unresolved type in the list,
-        * return typecheck_MAYBE.
-     */
-    mlist = merged->list;
-    i = merged->count;
-    while (i--) {
-               if (IS_CLASSREF(*mlist)) {
-                       return typecheck_MAYBE;
-               }
-               if (!(mlist->cls->state & CLASS_LINKED))
-                       if (!link_class(mlist->cls))
-                               return typecheck_FAIL;
-               if (!class_issubclass(mlist->cls,cls))
-                       return typecheck_FALSE;
-               mlist++;
-    }
-    return typecheck_TRUE;
-}
-
-/* typeinfo_is_assignable_to_class *********************************************
-   Check if a type is assignable to a given class type.
-   
-   IN:
-       value............the type of the value
-          dest.............the type of the destination
-
-   RETURN VALUE:
-       typecheck_TRUE...the type is assignable
-          typecheck_FALSE..the type is not assignable
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result
-typeinfo_is_assignable_to_class(typeinfo_t *value,classref_or_classinfo dest)
-{
-       classref_or_classinfo c;
-    classinfo *cls;
-       utf *classname;
-
-       TYPEINFO_ASSERT(value);
-
-    c = value->typeclass;
-
-    /* assignments of primitive values are not checked here. */
-    if (!c.any && !dest.any)
-        return typecheck_TRUE;
-
-    /* primitive and reference types are not assignment compatible. */
-    if (!c.any || !dest.any)
-        return typecheck_FALSE;
-
-    /* the null type can be assigned to any type */
-    if (TYPEINFO_IS_NULLTYPE(*value))
-        return typecheck_TRUE;
-
-    /* uninitialized objects are not assignable */
-    if (TYPEINFO_IS_NEWOBJECT(*value))
-        return typecheck_FALSE;
-
-       if (IS_CLASSREF(c)) {
-               /* The value type is an unresolved class reference. */
-               classname = c.ref->name;
-       }
-       else {
-               classname = c.cls->name;
-       }
-
-       if (IS_CLASSREF(dest)) {
-               /* the destination type is an unresolved class reference */
-               /* In this case we cannot tell a lot about assignability. */
-
-               /* the common case of value and dest type having the same classname */
-               if (dest.ref->name == classname && !value->merged)
-                       return typecheck_TRUE;
-
-               /* we cannot tell if value is assignable to dest, so we */
-               /* leave it up to the resolving code to check this      */
-               return typecheck_MAYBE;
-       }
-
-       /* { we know that dest is a loaded class } */
-
-       if (IS_CLASSREF(c)) {
-               /* the value type is an unresolved class reference */
-               
-               /* the common case of value and dest type having the same classname */
-               if (dest.cls->name == classname)
-                       return typecheck_TRUE;
-
-               /* we cannot tell if value is assignable to dest, so we */
-               /* leave it up to the resolving code to check this      */
-               return typecheck_MAYBE;
-       }
-
-       /* { we know that both c and dest are loaded classes } */
-       /* (c may still have a merged list containing unresolved classrefs!) */
-
-       TYPEINFO_ASSERT(!IS_CLASSREF(c));
-       TYPEINFO_ASSERT(!IS_CLASSREF(dest));
-
-       cls = c.cls;
-       
-       TYPEINFO_ASSERT(cls->state & CLASS_LOADED);
-       TYPEINFO_ASSERT(dest.cls->state & CLASS_LOADED);
-
-       /* maybe we need to link the classes */
-       if (!(cls->state & CLASS_LINKED))
-               if (!link_class(cls))
-                       return typecheck_FAIL;
-       if (!(dest.cls->state & CLASS_LINKED))
-               if (!link_class(dest.cls))
-                       return typecheck_FAIL;
-
-       /* { we know that both c and dest are linked classes } */
-       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
-       TYPEINFO_ASSERT(dest.cls->state & CLASS_LINKED);
-
-    if (dest.cls->flags & ACC_INTERFACE) {
-        /* We are assigning to an interface type. */
-        return merged_implements_interface(cls,value->merged,dest.cls);
-    }
-
-    if (CLASSINFO_IS_ARRAY(dest.cls)) {
-               arraydescriptor *arraydesc = dest.cls->vftbl->arraydesc;
-               int dimension = arraydesc->dimension;
-               classinfo *elementclass = (arraydesc->elementvftbl)
-                       ? arraydesc->elementvftbl->clazz : NULL;
-                       
-        /* We are assigning to an array type. */
-        if (!TYPEINFO_IS_ARRAY(*value))
-            return typecheck_FALSE;
-
-        /* {Both value and dest.cls are array types.} */
-
-        /* value must have at least the dimension of dest.cls. */
-        if (value->dimension < dimension)
-            return typecheck_FALSE;
-
-        if (value->dimension > dimension) {
-            /* value has higher dimension so we need to check
-             * if its component array can be assigned to the
-             * element type of dest.cls */
-
-                       if (!elementclass) return typecheck_FALSE;
-            
-            if (elementclass->flags & ACC_INTERFACE) {
-                /* We are assigning to an interface type. */
-                return classinfo_implements_interface(pseudo_class_Arraystub,
-                                                      elementclass);
-            }
-
-            /* We are assigning to a class type. */
-            return class_issubclass(pseudo_class_Arraystub,elementclass);
-        }
-
-        /* {value and dest.cls have the same dimension} */
-
-        if (value->elementtype != arraydesc->elementtype)
-            return typecheck_FALSE;
-
-        if (value->elementclass.any) {
-            /* We are assigning an array of objects so we have to
-             * check if the elements are assignable.
-             */
-
-            if (elementclass->flags & ACC_INTERFACE) {
-                /* We are assigning to an interface type. */
-
-                return merged_implements_interface(value->elementclass.cls,
-                                                   value->merged,
-                                                   elementclass);
-            }
-            
-            /* We are assigning to a class type. */
-            return merged_is_subclass(value->elementclass.cls,value->merged,elementclass);
-        }
-
-        return typecheck_TRUE;
-    }
-
-    /* {dest.cls is not an array} */
-    /* {dest.cls is a loaded class} */
-
-       /* If there are any unresolved references in the merged list, we cannot */
-       /* tell if the assignment will be ok.                                   */
-       /* This can only happen when cls is java.lang.Object                    */
-       if (cls == class_java_lang_Object && value->merged) {
-               classref_or_classinfo *mlist = value->merged->list;
-               int i = value->merged->count;
-               while (i--)
-                       if (IS_CLASSREF(*mlist++))
-                               return typecheck_MAYBE;
-       }
-        
-    /* We are assigning to a class type */
-    if (cls->flags & ACC_INTERFACE)
-        cls = class_java_lang_Object;
-    
-    return merged_is_subclass(cls,value->merged,dest.cls);
-}
-
-/* typeinfo_is_assignable ******************************************************
-   Check if a type is assignable to a given type.
-   
-   IN:
-       value............the type of the value
-          dest.............the type of the destination, must not be a merged type
-
-   RETURN VALUE:
-       typecheck_TRUE...the type is assignable
-          typecheck_FALSE..the type is not assignable
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result
-typeinfo_is_assignable(typeinfo_t *value,typeinfo_t *dest)
-{
-       TYPEINFO_ASSERT(value);
-       TYPEINFO_ASSERT(dest);
-       TYPEINFO_ASSERT(dest->merged == NULL);
-
-       return typeinfo_is_assignable_to_class(value,dest->typeclass);
-}
-
-/**********************************************************************/
-/* INITIALIZATION FUNCTIONS                                           */
-/* The following functions fill in uninitialized typeinfo structures. */
-/**********************************************************************/
-
-/* typeinfo_init_classinfo *****************************************************
-   Initialize a typeinfo to a resolved class.
-   
-   IN:
-          c................the class
-
-   OUT:
-       *info............is initialized
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-void
-typeinfo_init_classinfo(typeinfo_t *info, classinfo *c)
-{
-       if ((info->typeclass.cls = c)->vftbl->arraydesc) {
-               if (c->vftbl->arraydesc->elementvftbl)
-                       info->elementclass.cls = c->vftbl->arraydesc->elementvftbl->clazz;
-               else
-                       info->elementclass.any = NULL;
-               info->dimension = c->vftbl->arraydesc->dimension;
-               info->elementtype = c->vftbl->arraydesc->elementtype;
-       }
-       else {
-               info->elementclass.any = NULL;
-               info->dimension = 0;
-               info->elementtype = 0;
-       }
-       info->merged = NULL;
-}
-
-/* typeinfo_init_class *********************************************************
-   Initialize a typeinfo to a possibly unresolved class type.
-   
-   IN:
-          c................the class type
-
-   OUT:
-       *info............is initialized
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typeinfo_init_class(typeinfo_t *info,classref_or_classinfo c)
-{
-       char *utf_ptr;
-       int len;
-       classinfo *cls;
-               
-       TYPEINFO_ASSERT(c.any);
-       TYPEINFO_ASSERT(info);
-
-       /* if necessary, try to resolve lazily */
-       if (!resolve_classref_or_classinfo(NULL /* XXX should know method */,
-                               c,resolveLazy,false,true,&cls))
-       {
-               return false;
-       }
-       
-       if (cls) {
-               typeinfo_init_classinfo(info,cls);
-               return true;
-       }
-
-       /* {the type could no be resolved lazily} */
-
-       info->typeclass.ref = c.ref;
-       info->elementclass.any = NULL;
-       info->dimension = 0;
-       info->merged = NULL;
-
-       /* handle array type references */
-       utf_ptr = c.ref->name->text;
-       len = c.ref->name->blength;
-       if (*utf_ptr == '[') {
-               /* count dimensions */
-               while (*utf_ptr == '[') {
-                       utf_ptr++;
-                       info->dimension++;
-                       len--;
-               }
-               if (*utf_ptr == 'L') {
-                       utf_ptr++;
-                       len -= 2;
-                       info->elementtype = ARRAYTYPE_OBJECT;
-                       info->elementclass.ref = class_get_classref(c.ref->referer,utf_new(utf_ptr,len));
-               }
-               else {
-                       /* an array with primitive element type */
-                       /* should have been resolved above */
-                       TYPEINFO_ASSERT(false);
-               }
-       }
-       return true;
-}
-
-/* typeinfo_init_from_typedesc *************************************************
-   Initialize a typeinfo from a typedesc.
-   
-   IN:
-          desc.............the typedesc
-
-   OUT:
-       *type............set to the TYPE_* constant of DESC (if type != NULL)
-       *info............receives the typeinfo (if info != NULL)
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(desc);
-
-#ifdef TYPEINFO_VERBOSE
-       fprintf(stderr,"typeinfo_init_from_typedesc(");
-       descriptor_debug_print_typedesc(stderr,desc);
-       fprintf(stderr,")\n");
-#endif
-
-       if (type)
-               *type = desc->type;
-
-       if (info) {
-               if (desc->type == TYPE_ADR) {
-                       TYPEINFO_ASSERT(desc->classref);
-                       if (!typeinfo_init_class(info,CLASSREF_OR_CLASSINFO(desc->classref)))
-                               return false;
-               }
-               else {
-                       TYPEINFO_INIT_PRIMITIVE(*info);
-               }
-       }
-       return true;
-}
-
-/* typeinfos_init_from_methoddesc **********************************************
-   Initialize an array of typeinfos and u1 TYPE_* values from a methoddesc.
-   
-   IN:
-       desc.............the methoddesc
-       buflen...........number of parameters the buffer can hold
-       twoword..........if true, use two parameter slots for two-word types
-
-   OUT:
-       *typebuf.........receives a TYPE_* constant for each parameter
-                        typebuf must be != NULL
-       *infobuf.........receives a typeinfo for each parameter
-                        infobuf must be != NULL
-       *returntype......receives a TYPE_* constant for the return type
-                        returntype may be NULL
-       *returntypeinfo..receives a typeinfo for the return type
-                        returntypeinfo may be NULL
-
-   RETURN VALUE:
-       true.............success
-       false............an exception has been thrown
-
-   NOTE:
-       If (according to BUFLEN) the buffers are to small to hold the
-          parameter types, an internal error is thrown. This must be
-          avoided by checking the number of parameters and allocating enough
-          space before calling this function.
-
-*******************************************************************************/
-
-bool
-typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,typeinfo_t *infobuf,
-                              int buflen,bool twoword,
-                              u1 *returntype,typeinfo_t *returntypeinfo)
-{
-       int i;
-    int args = 0;
-
-       TYPEINFO_ASSERT(desc);
-       TYPEINFO_ASSERT(typebuf);
-       TYPEINFO_ASSERT(infobuf);
-
-#ifdef TYPEINFO_VERBOSE
-       fprintf(stderr,"typeinfos_init_from_methoddesc(");
-       descriptor_debug_print_methoddesc(stderr,desc);
-       fprintf(stderr,")\n");
-#endif
-
-    /* check arguments */
-    for (i=0; i<desc->paramcount; ++i) {
-               if (++args > buflen) {
-                       exceptions_throw_internalerror("Buffer too small for method arguments.");
-                       return false;
-               }
-
-               if (!typeinfo_init_from_typedesc(desc->paramtypes + i,typebuf++,infobuf++))
-                       return false;
-               
-               if (twoword && (typebuf[-1] == TYPE_LNG || typebuf[-1] == TYPE_DBL)) {
-                       if (++args > buflen) {
-                               exceptions_throw_internalerror("Buffer too small for method arguments.");
-                               return false;
-                       }
-
-                       *typebuf++ = TYPE_VOID;
-                       TYPEINFO_INIT_PRIMITIVE(*infobuf);
-                       infobuf++;
-               }
-    }
-
-    /* check returntype */
-    if (returntype) {
-               if (!typeinfo_init_from_typedesc(&(desc->returntype),returntype,returntypeinfo))
-                       return false;
-       }
-
-       return true;
-}
-
-/* typedescriptor_init_from_typedesc *******************************************
-   Initialize a typedescriptor from a typedesc.
-   
-   IN:
-          desc.............the typedesc
-
-   OUT:
-       *td..............receives the typedescriptor
-                           td must be != NULL
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typedescriptor_init_from_typedesc(typedescriptor_t *td,
-                                                                 typedesc *desc)
-{
-       TYPEINFO_ASSERT(td);
-       TYPEINFO_ASSERT(desc);
-
-       td->type = desc->type;
-       if (td->type == TYPE_ADR) {
-               if (!typeinfo_init_class(&(td->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref)))
-                       return false;
-       }
-       else {
-               TYPEINFO_INIT_PRIMITIVE(td->typeinfo);
-       }
-       return true;
-}
-
-/* typeinfo_init_varinfo_from_typedesc *****************************************
-   Initialize a varinfo from a typedesc.
-   
-   IN:
-          desc.............the typedesc
-
-   OUT:
-       *var.............receives the type
-                           var must be != NULL
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typeinfo_init_varinfo_from_typedesc(varinfo *var,
-                                                                 typedesc *desc)
-{
-       TYPEINFO_ASSERT(var);
-       TYPEINFO_ASSERT(desc);
-
-       var->type = desc->type;
-       if (var->type == TYPE_ADR) {
-               if (!typeinfo_init_class(&(var->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref)))
-                       return false;
-       }
-       else {
-               TYPEINFO_INIT_PRIMITIVE(var->typeinfo);
-       }
-       return true;
-}
-
-/* typeinfo_init_varinfos_from_methoddesc **************************************
-   Initialize an array of varinfos from a methoddesc.
-   
-   IN:
-       desc.............the methoddesc
-       buflen...........number of parameters the buffer can hold
-          startindex.......the zero-based index of the first parameter to
-                           write to the array. In other words the number of
-                                               parameters to skip at the beginning of the methoddesc.
-          map..............map from parameter indices to varinfo indices
-                           (indexed like jitdata.local_map)
-
-   OUT:
-       *vars............array receiving the varinfos
-                           td[0] receives the type of the
-                                               (startindex+1)th parameter of the method
-       *returntype......receives the typedescriptor of the return type.
-                           returntype may be NULL
-
-   RETURN VALUE:
-       true.............everything ok
-          false............an exception has been thrown
-
-   NOTE:
-       If (according to BUFLEN) the buffer is to small to hold the
-          parameter types, an internal error is thrown. This must be
-          avoided by checking the number of parameters and allocating enough
-          space before calling this function.
-
-*******************************************************************************/
-
-bool
-typeinfo_init_varinfos_from_methoddesc(varinfo *vars,
-                                                                        methoddesc *desc,
-                                                                        int buflen, int startindex,
-                                                                        s4 *map,
-                                                                        typedescriptor_t *returntype)
-{
-       s4 i;
-    s4 varindex;
-       s4 type;
-       s4 slot = 0;
-
-       /* skip arguments */
-       for (i=0; i<startindex; ++i) {
-               slot++;
-               if (IS_2_WORD_TYPE(desc->paramtypes[i].type))
-                       slot++;
-       }
-
-    /* check arguments */
-    for (i=startindex; i<desc->paramcount; ++i) {
-               type = desc->paramtypes[i].type;
-               varindex = map[5*slot + type];
-
-               slot++;
-               if (IS_2_WORD_TYPE(type))
-                       slot++;
-
-               if (varindex == UNUSED)
-                       continue;
-
-               if (varindex >= buflen) {
-                       exceptions_throw_internalerror("Buffer too small for method arguments.");
-                       return false;
-               }
-
-               if (!typeinfo_init_varinfo_from_typedesc(vars + varindex, desc->paramtypes + i))
-                       return false;
-    }
-
-    /* check returntype */
-    if (returntype) {
-               if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
-                       return false;
-       }
-
-       return true;
-}
-
-/* typedescriptors_init_from_methoddesc ****************************************
-   Initialize an array of typedescriptors from a methoddesc.
-   
-   IN:
-       desc.............the methoddesc
-       buflen...........number of parameters the buffer can hold
-       twoword..........if true, use two parameter slots for two-word types
-          startindex.......the zero-based index of the first parameter to
-                           write to the array. In other words the number of
-                                               parameters to skip at the beginning of the methoddesc.
-
-   OUT:
-       *td..............array receiving the typedescriptors.
-                           td[0] receives the typedescriptor of the
-                                               (startindex+1)th parameter of the method
-       *returntype......receives the typedescriptor of the return type.
-                           returntype may be NULL
-
-   RETURN VALUE:
-       >= 0.............number of typedescriptors filled in TD
-          -1...............an exception has been thrown
-
-   NOTE:
-       If (according to BUFLEN) the buffer is to small to hold the
-          parameter types, an internal error is thrown. This must be
-          avoided by checking the number of parameters and allocating enough
-          space before calling this function.
-
-*******************************************************************************/
-
-int
-typedescriptors_init_from_methoddesc(typedescriptor_t *td,
-                                                                        methoddesc *desc,
-                                                                        int buflen,bool twoword,int startindex,
-                                                                        typedescriptor_t *returntype)
-{
-       int i;
-    int args = 0;
-
-    /* check arguments */
-    for (i=startindex; i<desc->paramcount; ++i) {
-               if (++args > buflen) {
-                       exceptions_throw_internalerror("Buffer too small for method arguments.");
-                       return -1;
-               }
-
-               if (!typedescriptor_init_from_typedesc(td,desc->paramtypes + i))
-                       return -1;
-               td++;
-
-               if (twoword && (td[-1].type == TYPE_LNG || td[-1].type == TYPE_DBL)) {
-                       if (++args > buflen) {
-                               exceptions_throw_internalerror("Buffer too small for method arguments.");
-                               return -1;
-                       }
-
-                       td->type = TYPE_VOID;
-                       TYPEINFO_INIT_PRIMITIVE(td->typeinfo);
-                       td++;
-               }
-    }
-
-    /* check returntype */
-    if (returntype) {
-               if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
-                       return -1;
-       }
-
-       return args;
-}
-
-/* typeinfo_init_component *****************************************************
-   Initialize a typeinfo with the component type of a given array type.
-   
-   IN:
-          srcarray.........the typeinfo of the array type
-
-   OUT:
-       *dst.............receives the typeinfo of the component type
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typeinfo_init_component(typeinfo_t *srcarray,typeinfo_t *dst)
-{
-       typeinfo_mergedlist_t *merged;
-
-       TYPEINFO_ASSERT(srcarray);
-       TYPEINFO_ASSERT(dst);
-
-    if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
-        TYPEINFO_INIT_NULLTYPE(*dst);
-        return true;
-    }
-    
-    if (!TYPEINFO_IS_ARRAY(*srcarray)) {
-               /* XXX should we make that a verify error? */
-               exceptions_throw_internalerror("Trying to access component of non-array");
-               return false;
-       }
-
-       /* save the mergedlist (maybe dst == srcarray) */
-
-       merged = srcarray->merged;
-
-       if (IS_CLASSREF(srcarray->typeclass)) {
-               constant_classref *comp;
-               comp = class_get_classref_component_of(srcarray->typeclass.ref);
-
-               if (comp) {
-                       if (!typeinfo_init_class(dst,CLASSREF_OR_CLASSINFO(comp)))
-                               return false;
-               }
-               else {
-                       TYPEINFO_INIT_PRIMITIVE(*dst);
-               }
-       }
-       else {
-               vftbl_t *comp;
-               
-               if (!(srcarray->typeclass.cls->state & CLASS_LINKED)) {
-                       if (!link_class(srcarray->typeclass.cls)) {
-                               return false;
-                       }
-               }
-
-               TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl);
-               TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl->arraydesc);
-
-               comp = srcarray->typeclass.cls->vftbl->arraydesc->componentvftbl;
-               if (comp)
-                       typeinfo_init_classinfo(dst,comp->clazz);
-               else
-                       TYPEINFO_INIT_PRIMITIVE(*dst);
-       }
-    
-    dst->merged = merged; /* XXX should we do a deep copy? */
-       return true;
-}
-
-/* typeinfo_clone **************************************************************
-   Create a deep copy of a typeinfo struct.
-   
-   IN:
-          src..............the typeinfo to copy
-
-   OUT:
-       *dest............receives the copy
-
-   NOTE:
-       If src == dest this function is a nop.
-
-*******************************************************************************/
-
-void
-typeinfo_clone(typeinfo_t *src,typeinfo_t *dest)
-{
-    int count;
-    classref_or_classinfo *srclist,*destlist;
-
-    if (src == dest)
-        return;
-    
-    *dest = *src;
-
-    if (src->merged) {
-        count = src->merged->count;
-        TYPEINFO_ALLOCMERGED(dest->merged,count);
-        dest->merged->count = count;
-
-        srclist = src->merged->list;
-        destlist = dest->merged->list;
-        while (count--)
-            *destlist++ = *srclist++;
-    }
-}
-
-/**********************************************************************/
-/* MISCELLANEOUS FUNCTIONS                                            */
-/**********************************************************************/
-
-/* typeinfo_free ***************************************************************
-   Free memory referenced by the given typeinfo. The typeinfo itself is not
-   freed.
-   
-   IN:
-       info.............the typeinfo
-
-*******************************************************************************/
-
-void
-typeinfo_free(typeinfo_t *info)
-{
-    TYPEINFO_FREEMERGED_IF_ANY(info->merged);
-    info->merged = NULL;
-}
-
-/**********************************************************************/
-/* MERGING FUNCTIONS                                                  */
-/* The following functions are used to merge the types represented by */
-/* two typeinfo structures into one typeinfo structure.               */
-/**********************************************************************/
-
-static
-void
-typeinfo_merge_error(methodinfo *m,char *str,typeinfo_t *x,typeinfo_t *y) {
-#ifdef TYPEINFO_VERBOSE
-    fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
-    fprintf(stderr,"Typeinfo x:\n");
-    typeinfo_print(stderr,x,1);
-    fprintf(stderr,"Typeinfo y:\n");
-    typeinfo_print(stderr,y,1);
-    log_text(str);
-#endif
-
-       exceptions_throw_verifyerror(m, str);
-}
-
-/* Condition: clsx != clsy. */
-/* Returns: true if dest was changed (currently always true). */
-static
-bool
-typeinfo_merge_two(typeinfo_t *dest,classref_or_classinfo clsx,classref_or_classinfo clsy)
-{
-       TYPEINFO_ASSERT(dest);
-    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-    TYPEINFO_ALLOCMERGED(dest->merged,2);
-    dest->merged->count = 2;
-
-       TYPEINFO_ASSERT(clsx.any != clsy.any);
-
-    if (clsx.any < clsy.any) {
-        dest->merged->list[0] = clsx;
-        dest->merged->list[1] = clsy;
-    }
-    else {
-        dest->merged->list[0] = clsy;
-        dest->merged->list[1] = clsx;
-    }
-
-    return true;
-}
-
-/* Returns: true if dest was changed. */
-static
-bool
-typeinfo_merge_add(typeinfo_t *dest,typeinfo_mergedlist_t *m,classref_or_classinfo cls)
-{
-    int count;
-    typeinfo_mergedlist_t *newmerged;
-    classref_or_classinfo *mlist,*newlist;
-
-    count = m->count;
-    mlist = m->list;
-
-    /* Check if cls is already in the mergedlist m. */
-    while (count--) {
-        if ((mlist++)->any == cls.any) { /* XXX check equal classrefs? */
-            /* cls is in the list, so m is the resulting mergedlist */
-            if (dest->merged == m)
-                return false;
-
-            /* We have to copy the mergedlist */
-            TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-            count = m->count;
-            TYPEINFO_ALLOCMERGED(dest->merged,count);
-            dest->merged->count = count;
-            newlist = dest->merged->list;
-            mlist = m->list;
-            while (count--) {
-                *newlist++ = *mlist++;
-            }
-            return true;
-        }
-    }
-
-    /* Add cls to the mergedlist. */
-    count = m->count;
-    TYPEINFO_ALLOCMERGED(newmerged,count+1);
-    newmerged->count = count+1;
-    newlist = newmerged->list;    
-    mlist = m->list;
-    while (count) {
-        if (mlist->any > cls.any)
-            break;
-        *newlist++ = *mlist++;
-        count--;
-    }
-    *newlist++ = cls;
-    while (count--) {
-        *newlist++ = *mlist++;
-    }
-
-    /* Put the new mergedlist into dest. */
-    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-    dest->merged = newmerged;
-    
-    return true;
-}
-
-/* Returns: true if dest was changed. */
-static
-bool
-typeinfo_merge_mergedlists(typeinfo_t *dest,typeinfo_mergedlist_t *x,
-                           typeinfo_mergedlist_t *y)
-{
-    int count = 0;
-    int countx,county;
-    typeinfo_mergedlist_t *temp,*result;
-    classref_or_classinfo *clsx,*clsy,*newlist;
-
-    /* count the elements that will be in the resulting list */
-    /* (Both lists are sorted, equal elements are counted only once.) */
-    clsx = x->list;
-    clsy = y->list;
-    countx = x->count;
-    county = y->count;
-    while (countx && county) {
-        if (clsx->any == clsy->any) {
-            clsx++;
-            clsy++;
-            countx--;
-            county--;
-        }
-        else if (clsx->any < clsy->any) {
-            clsx++;
-            countx--;
-        }
-        else {
-            clsy++;
-            county--;
-        }
-        count++;
-    }
-    count += countx + county;
-
-    /* {The new mergedlist will have count entries.} */
-
-    if ((x->count != count) && (y->count == count)) {
-        temp = x; x = y; y = temp;
-    }
-    /* {If one of x,y is already the result it is x.} */
-    if (x->count == count) {
-        /* x->merged is equal to the result */
-        if (x == dest->merged)
-            return false;
-
-        if (!dest->merged || dest->merged->count != count) {
-            TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-            TYPEINFO_ALLOCMERGED(dest->merged,count);
-            dest->merged->count = count;
-        }
-
-        newlist = dest->merged->list;
-        clsx = x->list;
-        while (count--) {
-            *newlist++ = *clsx++;
-        }
-        return true;
-    }
-
-    /* {We have to merge two lists.} */
-
-    /* allocate the result list */
-    TYPEINFO_ALLOCMERGED(result,count);
-    result->count = count;
-    newlist = result->list;
-
-    /* merge the sorted lists */
-    clsx = x->list;
-    clsy = y->list;
-    countx = x->count;
-    county = y->count;
-    while (countx && county) {
-        if (clsx->any == clsy->any) {
-            *newlist++ = *clsx++;
-            clsy++;
-            countx--;
-            county--;
-        }
-        else if (clsx->any < clsy->any) {
-            *newlist++ = *clsx++;
-            countx--;
-        }
-        else {
-            *newlist++ = *clsy++;
-            county--;
-        }
-    }
-    while (countx--)
-            *newlist++ = *clsx++;
-    while (county--)
-            *newlist++ = *clsy++;
-
-    /* replace the list in dest with the result list */
-    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-    dest->merged = result;
-
-    return true;
-}
-
-/* typeinfo_merge_nonarrays ****************************************************
-   Merge two non-array types.
-   
-   IN:
-       x................the first type
-          y................the second type
-          mergedx..........merged list of the first type, may be NULL
-          mergedy..........merged list of the descond type, may be NULL
-
-   OUT:
-       *dest............receives the resulting merged list
-          *result..........receives the resulting type
-
-   RETURN VALUE:
-       typecheck_TRUE...*dest has been modified
-          typecheck_FALSE..*dest has not been modified
-          typecheck_FAIL...an exception has been thrown
-
-   NOTE:
-       RESULT is an extra parameter so it can point to dest->typeclass or to
-          dest->elementclass.
-
-*******************************************************************************/
-
-static typecheck_result
-typeinfo_merge_nonarrays(typeinfo_t *dest,
-                         classref_or_classinfo *result,
-                         classref_or_classinfo x,classref_or_classinfo y,
-                         typeinfo_mergedlist_t *mergedx,
-                         typeinfo_mergedlist_t *mergedy)
-{
-       classref_or_classinfo t;
-    classinfo *tcls,*common;
-    typeinfo_mergedlist_t *tmerged;
-    bool changed;
-       typecheck_result r;
-       utf *xname;
-       utf *yname;
-
-       TYPEINFO_ASSERT(dest && result && x.any && y.any);
-       TYPEINFO_ASSERT(x.cls != pseudo_class_Null);
-       TYPEINFO_ASSERT(y.cls != pseudo_class_Null);
-       TYPEINFO_ASSERT(x.cls != pseudo_class_New);
-       TYPEINFO_ASSERT(y.cls != pseudo_class_New);
-
-       /*--------------------------------------------------*/
-       /* common cases                                     */
-       /*--------------------------------------------------*/
-
-    /* Common case 1: x and y are the same class or class reference */
-    /* (This case is very simple unless *both* x and y really represent
-     *  merges of subclasses of clsx==clsy.)
-     */
-    if ( (x.any == y.any) && (!mergedx || !mergedy) ) {
-  return_simple_x:
-        /* DEBUG */ /* log_text("return simple x"); */
-        changed = (dest->merged != NULL);
-        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-        dest->merged = NULL;
-        *result = x;
-        /* DEBUG */ /* log_text("returning"); */
-        return changed;
-    }
-
-       xname = (IS_CLASSREF(x)) ? x.ref->name : x.cls->name;
-       yname = (IS_CLASSREF(y)) ? y.ref->name : y.cls->name;
-
-       /* Common case 2: xname == yname, at least one unresolved */
-    if ((IS_CLASSREF(x) || IS_CLASSREF(y)) && (xname == yname))
-       {
-               /* use the loaded one if any */
-               if (!IS_CLASSREF(y))
-                       x = y;
-               goto return_simple_x;
-    }
-
-       /*--------------------------------------------------*/
-       /* non-trivial cases                                */
-       /*--------------------------------------------------*/
-
-#ifdef TYPEINFO_VERBOSE
-       {
-               typeinfo_t dbgx,dbgy;
-               fprintf(stderr,"merge_nonarrays:\n");
-               fprintf(stderr,"    ");if(IS_CLASSREF(x))fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,xname);fprintf(stderr,"\n");
-               fprintf(stderr,"    ");if(IS_CLASSREF(y))fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,yname);fprintf(stderr,"\n");
-               fflush(stderr);
-               typeinfo_init_class(&dbgx,x);
-               dbgx.merged = mergedx;
-               typeinfo_init_class(&dbgy,y);
-               dbgy.merged = mergedy;
-               typeinfo_print(stderr,&dbgx,4);
-               fprintf(stderr,"  with:\n");
-               typeinfo_print(stderr,&dbgy,4);
-       }
-#endif
-
-       TYPEINFO_ASSERT(IS_CLASSREF(x) || (x.cls->state & CLASS_LOADED));
-       TYPEINFO_ASSERT(IS_CLASSREF(y) || (y.cls->state & CLASS_LOADED));
-
-    /* If y is unresolved or an interface, swap x and y. */
-    if (IS_CLASSREF(y) || (!IS_CLASSREF(x) && y.cls->flags & ACC_INTERFACE))
-       {
-        t = x; x = y; y = t;
-        tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
-    }
-       
-    /* {We know: If only one of x,y is unresolved it is x,} */
-    /* {         If both x,y are resolved and only one of x,y is an interface it is x.} */
-
-       if (IS_CLASSREF(x)) {
-               /* {We know: x and y have different class names} */
-               
-        /* Check if we are merging an unresolved type with java.lang.Object */
-        if (y.cls == class_java_lang_Object && !mergedy) {
-            x = y;
-            goto return_simple_x;
-        }
-            
-               common = class_java_lang_Object;
-               goto merge_with_simple_x;
-       }
-
-       /* {We know: both x and y are resolved} */
-    /* {We know: If only one of x,y is an interface it is x.} */
-
-       TYPEINFO_ASSERT(!IS_CLASSREF(x) && !IS_CLASSREF(y));
-       TYPEINFO_ASSERT(x.cls->state & CLASS_LOADED);
-       TYPEINFO_ASSERT(y.cls->state & CLASS_LOADED);
-
-    /* Handle merging of interfaces: */
-    if (x.cls->flags & ACC_INTERFACE) {
-        /* {x.cls is an interface and mergedx == NULL.} */
-        
-        if (y.cls->flags & ACC_INTERFACE) {
-            /* We are merging two interfaces. */
-            /* {mergedy == NULL} */
-
-            /* {We know that x.cls!=y.cls (see common case at beginning.)} */
-            result->cls = class_java_lang_Object;
-            return typeinfo_merge_two(dest,x,y);
-        }
-
-        /* {We know: x is an interface, y is a class.} */
-
-        /* Check if we are merging an interface with java.lang.Object */
-        if (y.cls == class_java_lang_Object && !mergedy) {
-            x = y;
-            goto return_simple_x;
-        }
-
-        /* If the type y implements x then the result of the merge
-         * is x regardless of mergedy.
-         */
-
-               /* we may have to link the classes */
-               if (!(x.cls->state & CLASS_LINKED))
-                       if (!link_class(x.cls))
-                               return typecheck_FAIL;
-               if (!(y.cls->state & CLASS_LINKED))
-                       if (!link_class(y.cls))
-                               return typecheck_FAIL;
-        
-               TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
-               TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
-
-        if (CLASSINFO_IMPLEMENTS_INTERFACE(y.cls,x.cls->index))
-               {
-            /* y implements x, so the result of the merge is x. */
-            goto return_simple_x;
-               }
-               
-        r = mergedlist_implements_interface(mergedy,x.cls);
-               if (r == typecheck_FAIL)
-                       return r;
-               if (r == typecheck_TRUE)
-        {
-            /* y implements x, so the result of the merge is x. */
-            goto return_simple_x;
-        }
-        
-        /* {We know: x is an interface, the type y a class or a merge
-         * of subclasses and is not guaranteed to implement x.} */
-
-        common = class_java_lang_Object;
-        goto merge_with_simple_x;
-    }
-
-    /* {We know: x and y are classes (not interfaces).} */
-    
-       /* we may have to link the classes */
-       if (!(x.cls->state & CLASS_LINKED))
-               if (!link_class(x.cls))
-                       return typecheck_FAIL;
-       if (!(y.cls->state & CLASS_LINKED))
-               if (!link_class(y.cls))
-                       return typecheck_FAIL;
-        
-       TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
-       TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
-
-    /* If *x is deeper in the inheritance hierarchy swap x and y. */
-    if (x.cls->index > y.cls->index) {
-        t = x; x = y; y = t;
-        tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
-    }
-
-    /* {We know: y is at least as deep in the hierarchy as x.} */
-
-    /* Find nearest common anchestor for the classes. */
-
-    common = x.cls;
-    tcls   = y.cls;
-
-    while (tcls->index > common->index)
-        tcls = tcls->super;
-
-    while (common != tcls) {
-        common = common->super;
-        tcls = tcls->super;
-    }
-
-    /* {common == nearest common anchestor of x and y.} */
-
-    /* If x.cls==common and x is a whole class (not a merge of subclasses)
-     * then the result of the merge is x.
-     */
-    if (x.cls == common && !mergedx) {
-        goto return_simple_x;
-    }
-   
-    if (mergedx) {
-        result->cls = common;
-        if (mergedy)
-            return typeinfo_merge_mergedlists(dest,mergedx,mergedy);
-        else
-            return typeinfo_merge_add(dest,mergedx,y);
-    }
-
-merge_with_simple_x:
-    result->cls = common;
-    if (mergedy)
-        return typeinfo_merge_add(dest,mergedy,x);
-    else
-        return typeinfo_merge_two(dest,x,y);
-}
-
-/* typeinfo_merge **************************************************************
-   Merge two types.
-   
-   IN:
-       m................method for exception messages
-       dest.............the first type
-       y................the second type
-
-   OUT:
-       *dest............receives the result of the merge
-
-   RETURN VALUE:
-       typecheck_TRUE...*dest has been modified
-       typecheck_FALSE..*dest has not been modified
-       typecheck_FAIL...an exception has been thrown
-
-   PRE-CONDITIONS:
-       1) *dest must be a valid initialized typeinfo
-       2) dest != y
-
-*******************************************************************************/
-
-typecheck_result
-typeinfo_merge(methodinfo *m,typeinfo_t *dest,typeinfo_t* y)
-{
-    typeinfo_t *x;
-    typeinfo_t *tmp;
-    classref_or_classinfo common;
-    classref_or_classinfo elementclass;
-    int dimension;
-    int elementtype;
-    bool changed;
-       typecheck_result r;
-
-       /*--------------------------------------------------*/
-       /* fast checks                                      */
-       /*--------------------------------------------------*/
-
-    /* Merging something with itself is a nop */
-    if (dest == y)
-        return typecheck_FALSE;
-
-    /* Merging two returnAddress types is ok. */
-       /* Merging two different returnAddresses never happens, as the verifier */
-       /* keeps them separate in order to check all the possible return paths  */
-       /* from JSR subroutines.                                                */
-    if (!dest->typeclass.any && !y->typeclass.any) {
-               TYPEINFO_ASSERT(TYPEINFO_RETURNADDRESS(*dest) ==  TYPEINFO_RETURNADDRESS(*y));
-        return typecheck_FALSE;
-       }
-    
-    /* Primitive types cannot be merged with reference types */
-       /* This must be checked before calls to typeinfo_merge.  */
-    TYPEINFO_ASSERT(dest->typeclass.any && y->typeclass.any);
-
-    /* handle uninitialized object types */
-    if (TYPEINFO_IS_NEWOBJECT(*dest) || TYPEINFO_IS_NEWOBJECT(*y)) {
-        if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y)) {
-            typeinfo_merge_error(m,"Trying to merge uninitialized object type.",dest,y);
-                       return typecheck_FAIL;
-               }
-        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest) != TYPEINFO_NEWOBJECT_INSTRUCTION(*y)) {
-            typeinfo_merge_error(m,"Trying to merge different uninitialized objects.",dest,y);
-                       return typecheck_FAIL;
-               }
-               /* the same uninitialized object -- no change */
-               return typecheck_FALSE;
-    }
-    
-       /*--------------------------------------------------*/
-       /* common cases                                     */
-       /*--------------------------------------------------*/
-
-    /* Common case: dest and y are the same class or class reference */
-    /* (This case is very simple unless *both* dest and y really represent
-     *  merges of subclasses of class dest==class y.)
-     */
-    if ((dest->typeclass.any == y->typeclass.any) && (!dest->merged || !y->merged)) {
-return_simple:
-        changed = (dest->merged != NULL);
-        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-        dest->merged = NULL;
-        return changed;
-    }
-    
-    /* Handle null types: */
-    if (TYPEINFO_IS_NULLTYPE(*y)) {
-        return typecheck_FALSE;
-    }
-    if (TYPEINFO_IS_NULLTYPE(*dest)) {
-        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-        TYPEINFO_CLONE(*y,*dest);
-        return typecheck_TRUE;
-    }
-
-       /* Common case: two types with the same name, at least one unresolved */
-       if (IS_CLASSREF(dest->typeclass)) {
-               if (IS_CLASSREF(y->typeclass)) {
-                       if (dest->typeclass.ref->name == y->typeclass.ref->name)
-                               goto return_simple;
-               }
-               else {
-                       /* XXX should we take y instead of dest here? */
-                       if (dest->typeclass.ref->name == y->typeclass.cls->name)
-                               goto return_simple;
-               }
-       }
-       else {
-               if (IS_CLASSREF(y->typeclass) 
-                   && (dest->typeclass.cls->name == y->typeclass.ref->name))
-               {
-                       goto return_simple;
-               }
-       }
-
-       /*--------------------------------------------------*/
-       /* non-trivial cases                                */
-       /*--------------------------------------------------*/
-
-#ifdef TYPEINFO_VERBOSE
-       fprintf(stderr,"merge:\n");
-    typeinfo_print(stderr,dest,4);
-    typeinfo_print(stderr,y,4);
-#endif
-
-    /* This function uses x internally, so x and y can be swapped
-     * without changing dest. */
-    x = dest;
-    changed = false;
-    
-    /* Handle merging of arrays: */
-    if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
-        
-        /* Make x the one with lesser dimension */
-        if (x->dimension > y->dimension) {
-            tmp = x; x = y; y = tmp;
-        }
-
-        /* If one array (y) has higher dimension than the other,
-         * interpret it as an array (same dim. as x) of Arraystubs. */
-        if (x->dimension < y->dimension) {
-            dimension = x->dimension;
-            elementtype = ARRAYTYPE_OBJECT;
-            elementclass.cls = pseudo_class_Arraystub;
-        }
-        else {
-            dimension = y->dimension;
-            elementtype = y->elementtype;
-            elementclass = y->elementclass;
-        }
-        
-        /* {The arrays are of the same dimension.} */
-        
-        if (x->elementtype != elementtype) {
-            /* Different element types are merged, so the resulting array
-             * type has one accessible dimension less. */
-            if (--dimension == 0) {
-                common.cls = pseudo_class_Arraystub;
-                elementtype = 0;
-                elementclass.any = NULL;
-            }
-            else {
-                common.cls = class_multiarray_of(dimension,pseudo_class_Arraystub,true);
-                               if (!common.cls) {
-                                       exceptions_throw_internalerror("XXX Coult not create array class");
-                                       return typecheck_FAIL;
-                               }
-
-                elementtype = ARRAYTYPE_OBJECT;
-                elementclass.cls = pseudo_class_Arraystub;
-            }
-        }
-        else {
-            /* {The arrays have the same dimension and elementtype.} */
-
-            if (elementtype == ARRAYTYPE_OBJECT) {
-                /* The elements are references, so their respective
-                 * types must be merged.
-                 */
-                               r = typeinfo_merge_nonarrays(dest,
-                                               &elementclass,
-                                               x->elementclass,
-                                               elementclass,
-                                               x->merged,y->merged);
-                               TYPEINFO_ASSERT(r != typecheck_MAYBE);
-                               if (r == typecheck_FAIL)
-                                       return r;
-                               changed |= r;
-
-                /* DEBUG */ /* log_text("finding resulting array class: "); */
-                               if (IS_CLASSREF(elementclass))
-                                       common.ref = class_get_classref_multiarray_of(dimension,elementclass.ref);
-                               else {
-                                       common.cls = class_multiarray_of(dimension,elementclass.cls,true);
-                                       if (!common.cls) {
-                                               exceptions_throw_internalerror("XXX Coult not create array class");
-                                               return typecheck_FAIL;
-                                       }
-                               }
-                /* DEBUG */ /* utf_display_printable_ascii(common->name); printf("\n"); */
-            }
-                       else {
-                               common.any = y->typeclass.any;
-                       }
-        }
-    }
-    else {
-        /* {We know that at least one of x or y is no array, so the
-         *  result cannot be an array.} */
-        
-               r = typeinfo_merge_nonarrays(dest,
-                               &common,
-                               x->typeclass,y->typeclass,
-                               x->merged,y->merged);
-               TYPEINFO_ASSERT(r != typecheck_MAYBE);
-               if (r == typecheck_FAIL)
-                       return r;
-               changed |= r;
-
-        dimension = 0;
-        elementtype = 0;
-        elementclass.any = NULL;
-    }
-
-    /* Put the new values into dest if neccessary. */
-
-    if (dest->typeclass.any != common.any) {
-        dest->typeclass.any = common.any;
-        changed = true;
-    }
-    if (dest->dimension != dimension) {
-        dest->dimension = dimension;
-        changed = true;
-    }
-    if (dest->elementtype != elementtype) {
-        dest->elementtype = elementtype;
-        changed = true;
-    }
-    if (dest->elementclass.any != elementclass.any) {
-        dest->elementclass.any = elementclass.any;
-        changed = true;
-    }
-
-    return changed;
-}
-#endif /* ENABLE_VERIFER */
-
-
-/**********************************************************************/
-/* DEBUGGING HELPERS                                                  */
-/**********************************************************************/
-
-#ifdef TYPEINFO_DEBUG
-
-#if 0
-static int
-typeinfo_test_compare(classref_or_classinfo *a,classref_or_classinfo *b)
-{
-    if (a->any == b->any) return 0;
-    if (a->any < b->any) return -1;
-    return +1;
-}
-
-static void
-typeinfo_test_parse(typeinfo_t *info,char *str)
-{
-    int num;
-    int i;
-    typeinfo_t *infobuf;
-    u1 *typebuf;
-    int returntype;
-    utf *desc = utf_new_char(str);
-    
-    num = typeinfo_count_method_args(desc,false);
-    if (num) {
-        typebuf = DMNEW(u1,num);
-        infobuf = DMNEW(typeinfo_t,num);
-        
-        typeinfo_init_from_method_args(desc,typebuf,infobuf,num,false,
-                                       &returntype,info);
-
-        TYPEINFO_ALLOCMERGED(info->merged,num);
-        info->merged->count = num;
-
-        for (i=0; i<num; ++i) {
-            if (typebuf[i] != TYPE_ADR) {
-                log_text("non-reference type in mergedlist");
-                               assert(0);
-                       }
-
-            info->merged->list[i].any = infobuf[i].typeclass.any;
-        }
-        qsort(info->merged->list,num,sizeof(classref_or_classinfo),
-              (int(*)(const void *,const void *))&typeinfo_test_compare);
-    }
-    else {
-        typeinfo_init_from_method_args(desc,NULL,NULL,0,false,
-                                       &returntype,info);
-    }
-}
-#endif
-
-#define TYPEINFO_TEST_BUFLEN  4000
-
-static bool
-typeinfo_equal(typeinfo_t *x,typeinfo_t *y)
-{
-    int i;
-    
-    if (x->typeclass.any != y->typeclass.any) return false;
-    if (x->dimension != y->dimension) return false;
-    if (x->dimension) {
-        if (x->elementclass.any != y->elementclass.any) return false;
-        if (x->elementtype != y->elementtype) return false;
-    }
-
-    if (TYPEINFO_IS_NEWOBJECT(*x))
-        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*x)
-            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
-            return false;
-
-    if (x->merged || y->merged) {
-        if (!(x->merged && y->merged)) return false;
-        if (x->merged->count != y->merged->count) return false;
-        for (i=0; i<x->merged->count; ++i)
-            if (x->merged->list[i].any != y->merged->list[i].any)
-                return false;
-    }
-    return true;
-}
-
-static void
-typeinfo_testmerge(typeinfo_t *a,typeinfo_t *b,typeinfo_t *result,int *failed)
-{
-    typeinfo_t dest;
-    bool changed,changed_should_be;
-       typecheck_result r;
-
-    TYPEINFO_CLONE(*a,dest);
-    
-    printf("\n          ");
-    typeinfo_print_short(stdout,&dest);
-    printf("\n          ");
-    typeinfo_print_short(stdout,b);
-    printf("\n");
-
-       r = typeinfo_merge(NULL,&dest,b);
-       if (r == typecheck_FAIL) {
-               printf("EXCEPTION\n");
-               return;
-       }
-    changed = (r) ? 1 : 0;
-    changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0;
-
-    printf("          %s\n",(changed) ? "changed" : "=");
-
-    if (typeinfo_equal(&dest,result)) {
-        printf("OK        ");
-        typeinfo_print_short(stdout,&dest);
-        printf("\n");
-        if (changed != changed_should_be) {
-            printf("WRONG RETURN VALUE!\n");
-            (*failed)++;
-        }
-    }
-    else {
-        printf("RESULT    ");
-        typeinfo_print_short(stdout,&dest);
-        printf("\n");
-        printf("SHOULD BE ");
-        typeinfo_print_short(stdout,result);
-        printf("\n");
-        (*failed)++;
-    }
-}
-
-#if 0
-static void
-typeinfo_inc_dimension(typeinfo_t *info)
-{
-    if (info->dimension++ == 0) {
-        info->elementtype = ARRAYTYPE_OBJECT;
-        info->elementclass = info->typeclass;
-    }
-    info->typeclass = class_array_of(info->typeclass,true);
-}
-#endif
-
-#define TYPEINFO_TEST_MAXDIM  10
-
-static void
-typeinfo_testrun(char *filename)
-{
-    char buf[TYPEINFO_TEST_BUFLEN];
-    char bufa[TYPEINFO_TEST_BUFLEN];
-    char bufb[TYPEINFO_TEST_BUFLEN];
-    char bufc[TYPEINFO_TEST_BUFLEN];
-    typeinfo_t a,b,c;
-    int maxdim;
-    int failed = 0;
-    FILE *file = fopen(filename,"rt");
-       int res;
-    
-    if (!file) {
-        log_text("could not open typeinfo test file");
-               assert(0);
-       }
-
-    while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) {
-        if (buf[0] == '#' || !strlen(buf))
-            continue;
-        
-        res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
-        if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc)) {
-            log_text("Invalid line in typeinfo test file (none of empty, comment or test)");
-                       assert(0);
-               }
-
-#if 0
-        typeinfo_test_parse(&a,bufa);
-        typeinfo_test_parse(&b,bufb);
-        typeinfo_test_parse(&c,bufc);
-#endif
-#if 0
-        do {
-#endif
-            typeinfo_testmerge(&a,&b,&c,&failed); /* check result */
-            typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */
-
-            if (TYPEINFO_IS_NULLTYPE(a)) break;
-            if (TYPEINFO_IS_NULLTYPE(b)) break;
-            if (TYPEINFO_IS_NULLTYPE(c)) break;
-            
-            maxdim = a.dimension;
-            if (b.dimension > maxdim) maxdim = b.dimension;
-            if (c.dimension > maxdim) maxdim = c.dimension;
-
-#if 0
-            if (maxdim < TYPEINFO_TEST_MAXDIM) {
-                typeinfo_inc_dimension(&a);
-                typeinfo_inc_dimension(&b);
-                typeinfo_inc_dimension(&c);
-            }
-        } while (maxdim < TYPEINFO_TEST_MAXDIM);
-#endif
-    }
-
-    fclose(file);
-
-    if (failed) {
-        fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed);
-        log_text("Failed test");
-               assert(0);
-    }
-}
-
-void
-typeinfo_test()
-{
-    log_text("Running typeinfo test file...");
-    typeinfo_testrun("typeinfo.tst");
-    log_text("Finished typeinfo test file.");
-}
-
-#if 0
-void
-typeinfo_init_from_fielddescriptor(typeinfo_t *info,char *desc)
-{
-    typeinfo_init_from_descriptor(info,desc,desc+strlen(desc));
-}
-#endif
-
-#define TYPEINFO_MAXINDENT  80
-
-void
-typeinfo_print_class(FILE *file,classref_or_classinfo c)
-{
-       /*fprintf(file,"<class %p>",c.any);*/
-
-       if (!c.any) {
-               fprintf(file,"<null>");
-       }
-       else {
-               if (IS_CLASSREF(c)) {
-                       fprintf(file,"<ref>");
-                       utf_fprint_printable_ascii(file,c.ref->name);
-               }
-               else {
-                       utf_fprint_printable_ascii(file,c.cls->name);
-               }
-       }
-}
-
-void
-typeinfo_print(FILE *file,typeinfo_t *info,int indent)
-{
-    int i;
-    char ind[TYPEINFO_MAXINDENT + 1];
-    instruction *ins;
-       basicblock *bptr;
-
-    if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
-    
-    for (i=0; i<indent; ++i)
-        ind[i] = ' ';
-    ind[i] = (char) 0;
-    
-    if (TYPEINFO_IS_PRIMITIVE(*info)) {
-               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
-               if (bptr)
-                       fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->nr);
-               else
-                       fprintf(file,"%sprimitive\n",ind);
-        return;
-    }
-    
-    if (TYPEINFO_IS_NULLTYPE(*info)) {
-        fprintf(file,"%snull\n",ind);
-        return;
-    }
-
-    if (TYPEINFO_IS_NEWOBJECT(*info)) {
-        ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
-        if (ins) {
-            fprintf(file,"%sNEW(%p):",ind,(void*)ins);
-                       typeinfo_print_class(file,ins[-1].sx.val.c);
-            fprintf(file,"\n");
-        }
-        else {
-            fprintf(file,"%sNEW(this)",ind);
-        }
-        return;
-    }
-
-    fprintf(file,"%sClass:      ",ind);
-       typeinfo_print_class(file,info->typeclass);
-    fprintf(file,"\n");
-
-    if (TYPEINFO_IS_ARRAY(*info)) {
-        fprintf(file,"%sDimension:    %d",ind,(int)info->dimension);
-        fprintf(file,"\n%sElements:     ",ind);
-        switch (info->elementtype) {
-          case ARRAYTYPE_INT     : fprintf(file,"int\n"); break;
-          case ARRAYTYPE_LONG    : fprintf(file,"long\n"); break;
-          case ARRAYTYPE_FLOAT   : fprintf(file,"float\n"); break;
-          case ARRAYTYPE_DOUBLE  : fprintf(file,"double\n"); break;
-          case ARRAYTYPE_BYTE    : fprintf(file,"byte\n"); break;
-          case ARRAYTYPE_CHAR    : fprintf(file,"char\n"); break;
-          case ARRAYTYPE_SHORT   : fprintf(file,"short\n"); break;
-          case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break;
-              
-          case ARRAYTYPE_OBJECT:
-                         typeinfo_print_class(file,info->elementclass);
-              fprintf(file,"\n");
-              break;
-              
-          default:
-              fprintf(file,"INVALID ARRAYTYPE!\n");
-        }
-    }
-
-    if (info->merged) {
-        fprintf(file,"%sMerged:     ",ind);
-        for (i=0; i<info->merged->count; ++i) {
-            if (i) fprintf(file,", ");
-                       typeinfo_print_class(file,info->merged->list[i]);
-        }
-        fprintf(file,"\n");
-    }
-}
-
-void
-typeinfo_print_short(FILE *file,typeinfo_t *info)
-{
-    int i;
-    instruction *ins;
-       basicblock *bptr;
-
-       /*fprintf(file,"<typeinfo %p>",info);*/
-
-       if (!info) {
-               fprintf(file,"(typeinfo*)NULL");
-               return;
-       }
-
-    if (TYPEINFO_IS_PRIMITIVE(*info)) {
-               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
-               if (bptr)
-                       fprintf(file,"ret(L%03d)",bptr->nr);
-               else
-                       fprintf(file,"primitive");
-        return;
-    }
-    
-    if (TYPEINFO_IS_NULLTYPE(*info)) {
-        fprintf(file,"null");
-        return;
-    }
-    
-    if (TYPEINFO_IS_NEWOBJECT(*info)) {
-        ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
-        if (ins) {
-                       /*fprintf(file,"<ins %p>",ins);*/
-            fprintf(file,"NEW(%p):",(void*)ins);
-                       typeinfo_print_class(file,ins[-1].sx.val.c);
-        }
-        else
-            fprintf(file,"NEW(this)");
-        return;
-    }
-
-    typeinfo_print_class(file,info->typeclass);
-
-    if (info->merged) {
-        fprintf(file,"{");
-        for (i=0; i<info->merged->count; ++i) {
-            if (i) fprintf(file,",");
-                       typeinfo_print_class(file,info->merged->list[i]);
-        }
-        fprintf(file,"}");
-    }
-}
-
-void
-typeinfo_print_type(FILE *file,int type,typeinfo_t *info)
-{
-    switch (type) {
-      case TYPE_VOID: fprintf(file,"V"); break;
-      case TYPE_INT:  fprintf(file,"I"); break;
-      case TYPE_FLT:  fprintf(file,"F"); break;
-      case TYPE_DBL:  fprintf(file,"D"); break;
-      case TYPE_LNG:  fprintf(file,"J"); break;
-         case TYPE_RET:  fprintf(file,"R:"); /* FALLTHROUGH! */
-      case TYPE_ADR:
-                 typeinfo_print_short(file,info);
-          break;
-          
-      default:
-          fprintf(file,"!");
-    }
-}
-
-void
-typedescriptor_print(FILE *file,typedescriptor_t *td)
-{
-       typeinfo_print_type(file,td->type,&(td->typeinfo));
-}
-
-void
-typevector_print(FILE *file,varinfo *vec,int size)
-{
-    int i;
-
-    for (i=0; i<size; ++i) {
-               fprintf(file," %d=",i);
-        typeinfo_print_type(file, vec[i].type, &(vec[i].typeinfo));
-    }
-}
-
-#endif /* TYPEINFO_DEBUG */
-
-
-/*
- * 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/jit/verify/typeinfo.cpp b/src/vm/jit/verify/typeinfo.cpp
new file mode 100644 (file)
index 0000000..f36ea24
--- /dev/null
@@ -0,0 +1,2572 @@
+/* src/vm/jit/verify/typeinfo.c - type system used by the type checker
+
+   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 <string.h>
+
+#include "mm/memory.h"
+
+#include "toolbox/logging.h"
+
+#include "vm/array.hpp"
+#include "vm/class.hpp"
+#include "vm/descriptor.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/globals.hpp"
+#include "vm/loader.hpp"
+#include "vm/primitive.hpp"
+#include "vm/resolve.hpp"
+
+#include "vm/jit/jit.hpp"
+#include "vm/jit/verify/typeinfo.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* check if a linked class is an array class. Only use for linked classes! */
+#define CLASSINFO_IS_ARRAY(clsinfo)  ((clsinfo)->vftbl->arraydesc != NULL)
+
+/* check if a linked class implements the interface with the given index */
+#define CLASSINFO_IMPLEMENTS_INTERFACE(cls,index)                   \
+    ( ((index) < (cls)->vftbl->interfacetablelength)            \
+      && ( (cls)->vftbl->interfacetable[-(index)] != NULL ) )
+
+/******************************************************************************/
+/* DEBUG HELPERS                                                              */
+/******************************************************************************/
+
+#ifdef TYPEINFO_DEBUG
+#define TYPEINFO_ASSERT(cond)  assert(cond)
+#else
+#define TYPEINFO_ASSERT(cond)
+#endif
+
+/**********************************************************************/
+/* TYPEVECTOR FUNCTIONS                                               */
+/**********************************************************************/
+
+#if defined(ENABLE_VERIFIER)
+
+/* typevector_copy *************************************************************
+   Return a copy of the given typevector.
+  
+   IN:
+          src..............typevector set to copy, must be != NULL
+          size.............number of elements per typevector
+
+   RETURN VALUE:
+       a pointer to the new typevector set
+
+*******************************************************************************/
+
+varinfo *
+typevector_copy(varinfo *src, int size)
+{
+       varinfo *dst;
+       
+       TYPEINFO_ASSERT(src);
+       
+       dst = DNEW_TYPEVECTOR(size);
+       memcpy(dst,src,TYPEVECTOR_SIZE(size));
+
+       return dst;
+}
+
+/* typevector_copy_inplace *****************************************************
+   Copy a typevector to a given destination.
+
+   IN:
+          src..............typevector to copy, must be != NULL
+          dst..............destination to write the copy to
+          size.............number of elements per typevector
+
+*******************************************************************************/
+
+void
+typevector_copy_inplace(varinfo *src,varinfo *dst,int size)
+{
+       memcpy(dst,src,TYPEVECTOR_SIZE(size));
+}
+
+/* typevector_checktype ********************************************************
+   Check if the typevector contains a given type at a given index.
+  
+   IN:
+          vec..............typevector set, must be != NULL
+          index............index of component to check
+          type.............TYPE_* constant to check against
+
+   RETURN VALUE:
+       true if the typevector contains TYPE at INDEX,
+          false otherwise
+
+*******************************************************************************/
+
+bool
+typevector_checktype(varinfo *vec,int index,int type)
+{
+       TYPEINFO_ASSERT(vec);
+
+       return vec[index].type == type;
+}
+
+/* typevector_checkreference ***************************************************
+   Check if the typevector contains a reference at a given index.
+  
+   IN:
+          vec..............typevector, must be != NULL
+          index............index of component to check
+
+   RETURN VALUE:
+       true if the typevector contains a reference at INDEX,
+          false otherwise
+
+*******************************************************************************/
+
+bool
+typevector_checkreference(varinfo *vec, int index)
+{
+       TYPEINFO_ASSERT(vec);
+       return TYPEDESC_IS_REFERENCE(vec[index]);
+}
+
+/* typevectorset_checkretaddr **************************************************
+   Check if the typevectors contains a returnAddress at a given index.
+  
+   IN:
+          vec..............typevector, must be != NULL
+          index............index of component to check
+
+   RETURN VALUE:
+       true if the typevector contains a returnAddress at INDEX,
+          false otherwise
+
+*******************************************************************************/
+
+bool
+typevector_checkretaddr(varinfo *vec,int index)
+{
+       TYPEINFO_ASSERT(vec);
+       return TYPEDESC_IS_RETURNADDRESS(vec[index]);
+}
+
+/* typevector_store ************************************************************
+   Store a type at a given index in the typevector.
+  
+   IN:
+          vec..............typevector set, must be != NULL
+          index............index of component to set
+          type.............TYPE_* constant of type to set
+          info.............typeinfo of type to set, may be NULL, 
+                           if TYPE != TYPE_ADR
+
+*******************************************************************************/
+
+void
+typevector_store(varinfo *vec,int index,int type,typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(vec);
+
+       vec[index].type = type;
+       if (info)
+               TYPEINFO_COPY(*info,vec[index].typeinfo);
+}
+
+/* typevector_store_retaddr ****************************************************
+   Store a returnAddress type at a given index in the typevector.
+  
+   IN:
+          vec..............typevector set, must be != NULL
+          index............index of component to set
+          info.............typeinfo of the returnAddress.
+
+*******************************************************************************/
+
+void
+typevector_store_retaddr(varinfo *vec,int index,typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(vec);
+       TYPEINFO_ASSERT(TYPEINFO_IS_PRIMITIVE(*info));
+       
+       vec[index].type = TYPE_ADR;
+       TYPEINFO_INIT_RETURNADDRESS(vec[index].typeinfo,
+                       TYPEINFO_RETURNADDRESS(*info));
+}
+
+/* typevector_init_object ******************************************************
+   Replace all uninitialized object types in the typevector set which were 
+   created by the given instruction by initialized object types.
+  
+   IN:
+          set..............typevector set
+          ins..............instruction which created the uninitialized object type
+          initclass........class of the initialized object type to set
+          size.............number of elements per typevector
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+   XXX maybe we should do the lazy resolving before calling this function
+
+*******************************************************************************/
+
+bool
+typevector_init_object(varinfo *set,void *ins,
+                                          classref_or_classinfo initclass,
+                                          int size)
+{
+       int i;
+
+       for (i=0; i<size; ++i) {
+               if (set[i].type == TYPE_ADR
+                       && TYPEINFO_IS_NEWOBJECT(set[i].typeinfo)
+                       && TYPEINFO_NEWOBJECT_INSTRUCTION(set[i].typeinfo) == ins)
+               {
+                       if (!typeinfo_init_class(&(set[i].typeinfo),initclass))
+                               return false;
+               }
+       }
+       return true;
+}
+
+/* typevector_merge ************************************************************
+   Merge a typevector with another one.
+   The given typevectors must have the same number of components.
+  
+   IN:
+       m................method for exception messages
+          dst..............the first typevector
+          y................the second typevector
+          size.............number of elements per typevector
+
+   OUT:
+       *dst.............the resulting typevector
+
+   RETURN VALUE:
+       typecheck_TRUE...dst has been modified
+          typecheck_FALSE..dst has not been modified
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result
+typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size)
+{
+       bool changed = false;
+       typecheck_result r;
+       
+       varinfo *a = dst;
+       varinfo *b = y;
+       while (size--) {
+               if (a->type != TYPE_VOID && a->type != b->type) {
+                       a->type = TYPE_VOID;
+                       changed = true;
+               }
+               else if (a->type == TYPE_ADR) {
+                       if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) {
+                               /* 'a' is a returnAddress */
+                               if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo)
+                                       || (TYPEINFO_RETURNADDRESS(a->typeinfo)
+                                               != TYPEINFO_RETURNADDRESS(b->typeinfo)))
+                               {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                       }
+                       else {
+                               /* 'a' is a reference */
+                               if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                               else {
+                                       /* two reference types are merged. There cannot be */
+                                       /* a merge error. In the worst case we get j.l.O.  */
+                                       r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo));
+                                       if (r == typecheck_FAIL)
+                                               return r;
+                                       changed |= r;
+                               }
+                       }
+               }
+               a++;
+               b++;
+       }
+       return (typecheck_result) changed;
+}
+
+/**********************************************************************/
+/* READ-ONLY FUNCTIONS                                                */
+/* The following functions don't change typeinfo data.                */
+/**********************************************************************/
+
+/* typeinfo_is_array ***********************************************************
+   Check whether a typeinfo describes an array type.
+   
+   IN:
+          info.............the typeinfo, must be != NULL
+
+   RETURN VALUE:
+       true if INFO describes an array type.
+
+*******************************************************************************/
+
+bool
+typeinfo_is_array(typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(info);
+    return TYPEINFO_IS_ARRAY(*info);
+}
+
+/* typeinfo_is_primitive_array *************************************************
+   Check whether a typeinfo describes a primitive array type.
+   
+   IN:
+          info.............the typeinfo, must be != NULL
+
+   RETURN VALUE:
+       true if INFO describes an array of a primitive type.
+
+*******************************************************************************/
+
+bool
+typeinfo_is_primitive_array(typeinfo_t *info,int arraytype)
+{
+       TYPEINFO_ASSERT(info);
+    return TYPEINFO_IS_PRIMITIVE_ARRAY(*info,arraytype);
+}
+
+/* typeinfo_is_array_of_refs ***************************************************
+   Check whether a typeinfo describes an array of references type.
+   
+   IN:
+          info.............the typeinfo, must be != NULL
+
+   RETURN VALUE:
+       true if INFO describes an array of a refrence type.
+
+*******************************************************************************/
+
+bool
+typeinfo_is_array_of_refs(typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(info);
+    return TYPEINFO_IS_ARRAY_OF_REFS(*info);
+}
+
+/* interface_extends_interface *************************************************
+   Check if a resolved interface extends a given resolved interface.
+   
+   IN:
+          cls..............the interface, must be linked
+          interf...........the interface to check against
+
+   RETURN VALUE:
+       true.............CLS extends INTERF
+          false............CLS does not extend INTERF
+
+*******************************************************************************/
+
+static bool
+interface_extends_interface(classinfo *cls,classinfo *interf)
+{
+    int i;
+    
+       TYPEINFO_ASSERT(cls);
+       TYPEINFO_ASSERT(interf);
+       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
+       TYPEINFO_ASSERT((cls->flags & ACC_INTERFACE) != 0);
+       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
+
+    /* first check direct superinterfaces */
+    for (i=0; i<cls->interfacescount; ++i) {
+        if (cls->interfaces[i] == interf)
+            return true;
+    }
+    
+    /* check indirect superinterfaces */
+    for (i=0; i<cls->interfacescount; ++i) {
+        if (interface_extends_interface(cls->interfaces[i],interf))
+            return true;
+    }
+    
+    return false;
+}
+
+/* classinfo_implements_interface **********************************************
+   Check if a resolved class implements a given resolved interface.
+   
+   IN:
+          cls..............the class
+          interf...........the interface
+
+   RETURN VALUE:
+       typecheck_TRUE...CLS implements INTERF
+          typecheck_FALSE..CLS does not implement INTERF
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+static typecheck_result
+classinfo_implements_interface(classinfo *cls,classinfo *interf)
+{
+       TYPEINFO_ASSERT(cls);
+       TYPEINFO_ASSERT(interf);
+       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
+
+       if (!(cls->state & CLASS_LINKED))
+               if (!link_class(cls))
+                       return typecheck_FAIL;
+
+    if (cls->flags & ACC_INTERFACE) {
+        /* cls is an interface */
+        if (cls == interf)
+            return typecheck_TRUE;
+
+        /* check superinterfaces */
+        return (typecheck_result) interface_extends_interface(cls,interf);
+    }
+
+       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
+    return (typecheck_result) CLASSINFO_IMPLEMENTS_INTERFACE(cls,interf->index);
+}
+
+/* mergedlist_implements_interface *********************************************
+   Check if all the classes in a given merged list implement a given resolved
+   interface.
+   
+   IN:
+          merged...........the list of merged class types
+          interf...........the interface to check against
+
+   RETURN VALUE:
+       typecheck_TRUE...all classes implement INTERF
+          typecheck_FALSE..there is at least one class that does not implement
+                           INTERF
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+static typecheck_result
+mergedlist_implements_interface(typeinfo_mergedlist_t *merged,
+                                classinfo *interf)
+{
+    int i;
+    classref_or_classinfo *mlist;
+       typecheck_result r;
+    
+       TYPEINFO_ASSERT(interf);
+       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
+
+    /* Check if there is an non-empty mergedlist. */
+    if (!merged)
+        return typecheck_FALSE;
+
+    /* If all classinfos in the (non-empty) merged array implement the
+     * interface return true, otherwise false.
+     */
+    mlist = merged->list;
+    i = merged->count;
+    while (i--) {
+               if (IS_CLASSREF(*mlist)) {
+                       return typecheck_MAYBE;
+               }
+        r = classinfo_implements_interface((mlist++)->cls,interf);
+        if (r != typecheck_TRUE)
+                       return r;
+    }
+    return typecheck_TRUE;
+}
+
+/* merged_implements_interface *************************************************
+   Check if a possible merged type implements a given resolved interface
+   interface.
+   
+   IN:
+       typeclass........(common) class of the (merged) type
+          merged...........the list of merged class types
+          interf...........the interface to check against
+
+   RETURN VALUE:
+       typecheck_TRUE...the type implement INTERF
+          typecheck_FALSE..the type does not implement INTERF
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+static typecheck_result
+merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist_t *merged,
+                            classinfo *interf)
+{
+       typecheck_result r;
+       
+    /* primitive types don't support interfaces. */
+    if (!typeclass)
+        return typecheck_FALSE;
+
+    /* the null type can be cast to any interface type. */
+    if (typeclass == pseudo_class_Null)
+        return typecheck_TRUE;
+
+    /* check if typeclass implements the interface. */
+    r = classinfo_implements_interface(typeclass,interf);
+       if (r != typecheck_FALSE)
+        return r;
+
+    /* check the mergedlist */
+       if (!merged)
+               return typecheck_FALSE;
+    return mergedlist_implements_interface(merged,interf);
+}
+
+/* merged_is_subclass **********************************************************
+   Check if a possible merged type is a subclass of a given class.
+   A merged type is a subclass of a class C if all types in the merged list
+   are subclasses of C. A sufficient condition for this is that the
+   common type of the merged type is a subclass of C.
+
+   IN:
+       typeclass........(common) class of the (merged) type
+                           MUST be a loaded and linked class
+          merged...........the list of merged class types
+          cls..............the class to theck against
+
+   RETURN VALUE:
+       typecheck_TRUE...the type is a subclass of CLS
+          typecheck_FALSE..the type is not a subclass of CLS
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+static typecheck_result
+merged_is_subclass(classinfo *typeclass,typeinfo_mergedlist_t *merged,
+               classinfo *cls)
+{
+    int i;
+    classref_or_classinfo *mlist;
+
+       TYPEINFO_ASSERT(cls);
+       
+    /* primitive types aren't subclasses of anything. */
+    if (!typeclass)
+        return typecheck_FALSE;
+
+    /* the null type can be cast to any reference type. */
+    if (typeclass == pseudo_class_Null)
+        return typecheck_TRUE;
+
+       TYPEINFO_ASSERT(typeclass->state & CLASS_LOADED);
+       TYPEINFO_ASSERT(typeclass->state & CLASS_LINKED);
+
+    /* check if the common typeclass is a subclass of CLS. */
+       if (class_issubclass(typeclass,cls))
+               return typecheck_TRUE;
+       
+    /* check the mergedlist */
+       if (!merged)
+               return typecheck_FALSE;
+    /* If all classinfos in the (non-empty) merged list are subclasses
+        * of CLS, return true, otherwise false.
+        * If there is at least one unresolved type in the list,
+        * return typecheck_MAYBE.
+     */
+    mlist = merged->list;
+    i = merged->count;
+    while (i--) {
+               if (IS_CLASSREF(*mlist)) {
+                       return typecheck_MAYBE;
+               }
+               if (!(mlist->cls->state & CLASS_LINKED))
+                       if (!link_class(mlist->cls))
+                               return typecheck_FAIL;
+               if (!class_issubclass(mlist->cls,cls))
+                       return typecheck_FALSE;
+               mlist++;
+    }
+    return typecheck_TRUE;
+}
+
+/* typeinfo_is_assignable_to_class *********************************************
+   Check if a type is assignable to a given class type.
+   
+   IN:
+       value............the type of the value
+          dest.............the type of the destination
+
+   RETURN VALUE:
+       typecheck_TRUE...the type is assignable
+          typecheck_FALSE..the type is not assignable
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result
+typeinfo_is_assignable_to_class(typeinfo_t *value,classref_or_classinfo dest)
+{
+       classref_or_classinfo c;
+    classinfo *cls;
+       utf *classname;
+
+       TYPEINFO_ASSERT(value);
+
+    c = value->typeclass;
+
+    /* assignments of primitive values are not checked here. */
+    if (!c.any && !dest.any)
+        return typecheck_TRUE;
+
+    /* primitive and reference types are not assignment compatible. */
+    if (!c.any || !dest.any)
+        return typecheck_FALSE;
+
+    /* the null type can be assigned to any type */
+    if (TYPEINFO_IS_NULLTYPE(*value))
+        return typecheck_TRUE;
+
+    /* uninitialized objects are not assignable */
+    if (TYPEINFO_IS_NEWOBJECT(*value))
+        return typecheck_FALSE;
+
+       if (IS_CLASSREF(c)) {
+               /* The value type is an unresolved class reference. */
+               classname = c.ref->name;
+       }
+       else {
+               classname = c.cls->name;
+       }
+
+       if (IS_CLASSREF(dest)) {
+               /* the destination type is an unresolved class reference */
+               /* In this case we cannot tell a lot about assignability. */
+
+               /* the common case of value and dest type having the same classname */
+               if (dest.ref->name == classname && !value->merged)
+                       return typecheck_TRUE;
+
+               /* we cannot tell if value is assignable to dest, so we */
+               /* leave it up to the resolving code to check this      */
+               return typecheck_MAYBE;
+       }
+
+       /* { we know that dest is a loaded class } */
+
+       if (IS_CLASSREF(c)) {
+               /* the value type is an unresolved class reference */
+               
+               /* the common case of value and dest type having the same classname */
+               if (dest.cls->name == classname)
+                       return typecheck_TRUE;
+
+               /* we cannot tell if value is assignable to dest, so we */
+               /* leave it up to the resolving code to check this      */
+               return typecheck_MAYBE;
+       }
+
+       /* { we know that both c and dest are loaded classes } */
+       /* (c may still have a merged list containing unresolved classrefs!) */
+
+       TYPEINFO_ASSERT(!IS_CLASSREF(c));
+       TYPEINFO_ASSERT(!IS_CLASSREF(dest));
+
+       cls = c.cls;
+       
+       TYPEINFO_ASSERT(cls->state & CLASS_LOADED);
+       TYPEINFO_ASSERT(dest.cls->state & CLASS_LOADED);
+
+       /* maybe we need to link the classes */
+       if (!(cls->state & CLASS_LINKED))
+               if (!link_class(cls))
+                       return typecheck_FAIL;
+       if (!(dest.cls->state & CLASS_LINKED))
+               if (!link_class(dest.cls))
+                       return typecheck_FAIL;
+
+       /* { we know that both c and dest are linked classes } */
+       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
+       TYPEINFO_ASSERT(dest.cls->state & CLASS_LINKED);
+
+    if (dest.cls->flags & ACC_INTERFACE) {
+        /* We are assigning to an interface type. */
+        return merged_implements_interface(cls,value->merged,dest.cls);
+    }
+
+    if (CLASSINFO_IS_ARRAY(dest.cls)) {
+               arraydescriptor *arraydesc = dest.cls->vftbl->arraydesc;
+               int dimension = arraydesc->dimension;
+               classinfo *elementclass = (arraydesc->elementvftbl)
+                       ? arraydesc->elementvftbl->clazz : NULL;
+                       
+        /* We are assigning to an array type. */
+        if (!TYPEINFO_IS_ARRAY(*value))
+            return typecheck_FALSE;
+
+        /* {Both value and dest.cls are array types.} */
+
+        /* value must have at least the dimension of dest.cls. */
+        if (value->dimension < dimension)
+            return typecheck_FALSE;
+
+        if (value->dimension > dimension) {
+            /* value has higher dimension so we need to check
+             * if its component array can be assigned to the
+             * element type of dest.cls */
+
+                       if (!elementclass) return typecheck_FALSE;
+            
+            if (elementclass->flags & ACC_INTERFACE) {
+                /* We are assigning to an interface type. */
+                return classinfo_implements_interface(pseudo_class_Arraystub,
+                                                      elementclass);
+            }
+
+            /* We are assigning to a class type. */
+            return (typecheck_result) class_issubclass(pseudo_class_Arraystub,elementclass);
+        }
+
+        /* {value and dest.cls have the same dimension} */
+
+        if (value->elementtype != arraydesc->elementtype)
+            return typecheck_FALSE;
+
+        if (value->elementclass.any) {
+            /* We are assigning an array of objects so we have to
+             * check if the elements are assignable.
+             */
+
+            if (elementclass->flags & ACC_INTERFACE) {
+                /* We are assigning to an interface type. */
+
+                return merged_implements_interface(value->elementclass.cls,
+                                                   value->merged,
+                                                   elementclass);
+            }
+            
+            /* We are assigning to a class type. */
+            return merged_is_subclass(value->elementclass.cls,value->merged,elementclass);
+        }
+
+        return typecheck_TRUE;
+    }
+
+    /* {dest.cls is not an array} */
+    /* {dest.cls is a loaded class} */
+
+       /* If there are any unresolved references in the merged list, we cannot */
+       /* tell if the assignment will be ok.                                   */
+       /* This can only happen when cls is java.lang.Object                    */
+       if (cls == class_java_lang_Object && value->merged) {
+               classref_or_classinfo *mlist = value->merged->list;
+               int i = value->merged->count;
+               while (i--)
+                       if (IS_CLASSREF(*mlist++))
+                               return typecheck_MAYBE;
+       }
+        
+    /* We are assigning to a class type */
+    if (cls->flags & ACC_INTERFACE)
+        cls = class_java_lang_Object;
+    
+    return merged_is_subclass(cls,value->merged,dest.cls);
+}
+
+/* typeinfo_is_assignable ******************************************************
+   Check if a type is assignable to a given type.
+   
+   IN:
+       value............the type of the value
+          dest.............the type of the destination, must not be a merged type
+
+   RETURN VALUE:
+       typecheck_TRUE...the type is assignable
+          typecheck_FALSE..the type is not assignable
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result
+typeinfo_is_assignable(typeinfo_t *value,typeinfo_t *dest)
+{
+       TYPEINFO_ASSERT(value);
+       TYPEINFO_ASSERT(dest);
+       TYPEINFO_ASSERT(dest->merged == NULL);
+
+       return typeinfo_is_assignable_to_class(value,dest->typeclass);
+}
+
+/**********************************************************************/
+/* INITIALIZATION FUNCTIONS                                           */
+/* The following functions fill in uninitialized typeinfo structures. */
+/**********************************************************************/
+
+/* typeinfo_init_classinfo *****************************************************
+   Initialize a typeinfo to a resolved class.
+   
+   IN:
+          c................the class
+
+   OUT:
+       *info............is initialized
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+void
+typeinfo_init_classinfo(typeinfo_t *info, classinfo *c)
+{
+       if ((info->typeclass.cls = c)->vftbl->arraydesc) {
+               if (c->vftbl->arraydesc->elementvftbl)
+                       info->elementclass.cls = c->vftbl->arraydesc->elementvftbl->clazz;
+               else
+                       info->elementclass.any = NULL;
+               info->dimension = c->vftbl->arraydesc->dimension;
+               info->elementtype = c->vftbl->arraydesc->elementtype;
+       }
+       else {
+               info->elementclass.any = NULL;
+               info->dimension = 0;
+               info->elementtype = 0;
+       }
+       info->merged = NULL;
+}
+
+/* typeinfo_init_class *********************************************************
+   Initialize a typeinfo to a possibly unresolved class type.
+   
+   IN:
+          c................the class type
+
+   OUT:
+       *info............is initialized
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typeinfo_init_class(typeinfo_t *info,classref_or_classinfo c)
+{
+       char *utf_ptr;
+       int len;
+       classinfo *cls;
+               
+       TYPEINFO_ASSERT(c.any);
+       TYPEINFO_ASSERT(info);
+
+       /* if necessary, try to resolve lazily */
+       if (!resolve_classref_or_classinfo(NULL /* XXX should know method */,
+                               c,resolveLazy,false,true,&cls))
+       {
+               return false;
+       }
+       
+       if (cls) {
+               typeinfo_init_classinfo(info,cls);
+               return true;
+       }
+
+       /* {the type could no be resolved lazily} */
+
+       info->typeclass.ref = c.ref;
+       info->elementclass.any = NULL;
+       info->dimension = 0;
+       info->merged = NULL;
+
+       /* handle array type references */
+       utf_ptr = c.ref->name->text;
+       len = c.ref->name->blength;
+       if (*utf_ptr == '[') {
+               /* count dimensions */
+               while (*utf_ptr == '[') {
+                       utf_ptr++;
+                       info->dimension++;
+                       len--;
+               }
+               if (*utf_ptr == 'L') {
+                       utf_ptr++;
+                       len -= 2;
+                       info->elementtype = ARRAYTYPE_OBJECT;
+                       info->elementclass.ref = class_get_classref(c.ref->referer,utf_new(utf_ptr,len));
+               }
+               else {
+                       /* an array with primitive element type */
+                       /* should have been resolved above */
+                       TYPEINFO_ASSERT(false);
+               }
+       }
+       return true;
+}
+
+/* typeinfo_init_from_typedesc *************************************************
+   Initialize a typeinfo from a typedesc.
+   
+   IN:
+          desc.............the typedesc
+
+   OUT:
+       *type............set to the TYPE_* constant of DESC (if type != NULL)
+       *info............receives the typeinfo (if info != NULL)
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(desc);
+
+#ifdef TYPEINFO_VERBOSE
+       fprintf(stderr,"typeinfo_init_from_typedesc(");
+       descriptor_debug_print_typedesc(stderr,desc);
+       fprintf(stderr,")\n");
+#endif
+
+       if (type)
+               *type = desc->type;
+
+       if (info) {
+               if (desc->type == TYPE_ADR) {
+                       TYPEINFO_ASSERT(desc->classref);
+                       if (!typeinfo_init_class(info,CLASSREF_OR_CLASSINFO(desc->classref)))
+                               return false;
+               }
+               else {
+                       TYPEINFO_INIT_PRIMITIVE(*info);
+               }
+       }
+       return true;
+}
+
+/* typeinfos_init_from_methoddesc **********************************************
+   Initialize an array of typeinfos and u1 TYPE_* values from a methoddesc.
+   
+   IN:
+       desc.............the methoddesc
+       buflen...........number of parameters the buffer can hold
+       twoword..........if true, use two parameter slots for two-word types
+
+   OUT:
+       *typebuf.........receives a TYPE_* constant for each parameter
+                        typebuf must be != NULL
+       *infobuf.........receives a typeinfo for each parameter
+                        infobuf must be != NULL
+       *returntype......receives a TYPE_* constant for the return type
+                        returntype may be NULL
+       *returntypeinfo..receives a typeinfo for the return type
+                        returntypeinfo may be NULL
+
+   RETURN VALUE:
+       true.............success
+       false............an exception has been thrown
+
+   NOTE:
+       If (according to BUFLEN) the buffers are to small to hold the
+          parameter types, an internal error is thrown. This must be
+          avoided by checking the number of parameters and allocating enough
+          space before calling this function.
+
+*******************************************************************************/
+
+bool
+typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,typeinfo_t *infobuf,
+                              int buflen,bool twoword,
+                              u1 *returntype,typeinfo_t *returntypeinfo)
+{
+       int i;
+    int args = 0;
+
+       TYPEINFO_ASSERT(desc);
+       TYPEINFO_ASSERT(typebuf);
+       TYPEINFO_ASSERT(infobuf);
+
+#ifdef TYPEINFO_VERBOSE
+       fprintf(stderr,"typeinfos_init_from_methoddesc(");
+       descriptor_debug_print_methoddesc(stderr,desc);
+       fprintf(stderr,")\n");
+#endif
+
+    /* check arguments */
+    for (i=0; i<desc->paramcount; ++i) {
+               if (++args > buflen) {
+                       exceptions_throw_internalerror("Buffer too small for method arguments.");
+                       return false;
+               }
+
+               if (!typeinfo_init_from_typedesc(desc->paramtypes + i,typebuf++,infobuf++))
+                       return false;
+               
+               if (twoword && (typebuf[-1] == TYPE_LNG || typebuf[-1] == TYPE_DBL)) {
+                       if (++args > buflen) {
+                               exceptions_throw_internalerror("Buffer too small for method arguments.");
+                               return false;
+                       }
+
+                       *typebuf++ = TYPE_VOID;
+                       TYPEINFO_INIT_PRIMITIVE(*infobuf);
+                       infobuf++;
+               }
+    }
+
+    /* check returntype */
+    if (returntype) {
+               if (!typeinfo_init_from_typedesc(&(desc->returntype),returntype,returntypeinfo))
+                       return false;
+       }
+
+       return true;
+}
+
+/* typedescriptor_init_from_typedesc *******************************************
+   Initialize a typedescriptor from a typedesc.
+   
+   IN:
+          desc.............the typedesc
+
+   OUT:
+       *td..............receives the typedescriptor
+                           td must be != NULL
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typedescriptor_init_from_typedesc(typedescriptor_t *td,
+                                                                 typedesc *desc)
+{
+       TYPEINFO_ASSERT(td);
+       TYPEINFO_ASSERT(desc);
+
+       td->type = desc->type;
+       if (td->type == TYPE_ADR) {
+               if (!typeinfo_init_class(&(td->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref)))
+                       return false;
+       }
+       else {
+               TYPEINFO_INIT_PRIMITIVE(td->typeinfo);
+       }
+       return true;
+}
+
+/* typeinfo_init_varinfo_from_typedesc *****************************************
+   Initialize a varinfo from a typedesc.
+   
+   IN:
+          desc.............the typedesc
+
+   OUT:
+       *var.............receives the type
+                           var must be != NULL
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typeinfo_init_varinfo_from_typedesc(varinfo *var,
+                                                                 typedesc *desc)
+{
+       TYPEINFO_ASSERT(var);
+       TYPEINFO_ASSERT(desc);
+
+       var->type = desc->type;
+       if (var->type == TYPE_ADR) {
+               if (!typeinfo_init_class(&(var->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref)))
+                       return false;
+       }
+       else {
+               TYPEINFO_INIT_PRIMITIVE(var->typeinfo);
+       }
+       return true;
+}
+
+/* typeinfo_init_varinfos_from_methoddesc **************************************
+   Initialize an array of varinfos from a methoddesc.
+   
+   IN:
+       desc.............the methoddesc
+       buflen...........number of parameters the buffer can hold
+          startindex.......the zero-based index of the first parameter to
+                           write to the array. In other words the number of
+                                               parameters to skip at the beginning of the methoddesc.
+          map..............map from parameter indices to varinfo indices
+                           (indexed like jitdata.local_map)
+
+   OUT:
+       *vars............array receiving the varinfos
+                           td[0] receives the type of the
+                                               (startindex+1)th parameter of the method
+       *returntype......receives the typedescriptor of the return type.
+                           returntype may be NULL
+
+   RETURN VALUE:
+       true.............everything ok
+          false............an exception has been thrown
+
+   NOTE:
+       If (according to BUFLEN) the buffer is to small to hold the
+          parameter types, an internal error is thrown. This must be
+          avoided by checking the number of parameters and allocating enough
+          space before calling this function.
+
+*******************************************************************************/
+
+bool
+typeinfo_init_varinfos_from_methoddesc(varinfo *vars,
+                                                                        methoddesc *desc,
+                                                                        int buflen, int startindex,
+                                                                        s4 *map,
+                                                                        typedescriptor_t *returntype)
+{
+       s4 i;
+    s4 varindex;
+       s4 type;
+       s4 slot = 0;
+
+       /* skip arguments */
+       for (i=0; i<startindex; ++i) {
+               slot++;
+               if (IS_2_WORD_TYPE(desc->paramtypes[i].type))
+                       slot++;
+       }
+
+    /* check arguments */
+    for (i=startindex; i<desc->paramcount; ++i) {
+               type = desc->paramtypes[i].type;
+               varindex = map[5*slot + type];
+
+               slot++;
+               if (IS_2_WORD_TYPE(type))
+                       slot++;
+
+               if (varindex == UNUSED)
+                       continue;
+
+               if (varindex >= buflen) {
+                       exceptions_throw_internalerror("Buffer too small for method arguments.");
+                       return false;
+               }
+
+               if (!typeinfo_init_varinfo_from_typedesc(vars + varindex, desc->paramtypes + i))
+                       return false;
+    }
+
+    /* check returntype */
+    if (returntype) {
+               if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
+                       return false;
+       }
+
+       return true;
+}
+
+/* typedescriptors_init_from_methoddesc ****************************************
+   Initialize an array of typedescriptors from a methoddesc.
+   
+   IN:
+       desc.............the methoddesc
+       buflen...........number of parameters the buffer can hold
+       twoword..........if true, use two parameter slots for two-word types
+          startindex.......the zero-based index of the first parameter to
+                           write to the array. In other words the number of
+                                               parameters to skip at the beginning of the methoddesc.
+
+   OUT:
+       *td..............array receiving the typedescriptors.
+                           td[0] receives the typedescriptor of the
+                                               (startindex+1)th parameter of the method
+       *returntype......receives the typedescriptor of the return type.
+                           returntype may be NULL
+
+   RETURN VALUE:
+       >= 0.............number of typedescriptors filled in TD
+          -1...............an exception has been thrown
+
+   NOTE:
+       If (according to BUFLEN) the buffer is to small to hold the
+          parameter types, an internal error is thrown. This must be
+          avoided by checking the number of parameters and allocating enough
+          space before calling this function.
+
+*******************************************************************************/
+
+int
+typedescriptors_init_from_methoddesc(typedescriptor_t *td,
+                                                                        methoddesc *desc,
+                                                                        int buflen,bool twoword,int startindex,
+                                                                        typedescriptor_t *returntype)
+{
+       int i;
+    int args = 0;
+
+    /* check arguments */
+    for (i=startindex; i<desc->paramcount; ++i) {
+               if (++args > buflen) {
+                       exceptions_throw_internalerror("Buffer too small for method arguments.");
+                       return -1;
+               }
+
+               if (!typedescriptor_init_from_typedesc(td,desc->paramtypes + i))
+                       return -1;
+               td++;
+
+               if (twoword && (td[-1].type == TYPE_LNG || td[-1].type == TYPE_DBL)) {
+                       if (++args > buflen) {
+                               exceptions_throw_internalerror("Buffer too small for method arguments.");
+                               return -1;
+                       }
+
+                       td->type = TYPE_VOID;
+                       TYPEINFO_INIT_PRIMITIVE(td->typeinfo);
+                       td++;
+               }
+    }
+
+    /* check returntype */
+    if (returntype) {
+               if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
+                       return -1;
+       }
+
+       return args;
+}
+
+/* typeinfo_init_component *****************************************************
+   Initialize a typeinfo with the component type of a given array type.
+   
+   IN:
+          srcarray.........the typeinfo of the array type
+
+   OUT:
+       *dst.............receives the typeinfo of the component type
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typeinfo_init_component(typeinfo_t *srcarray,typeinfo_t *dst)
+{
+       typeinfo_mergedlist_t *merged;
+
+       TYPEINFO_ASSERT(srcarray);
+       TYPEINFO_ASSERT(dst);
+
+    if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
+        TYPEINFO_INIT_NULLTYPE(*dst);
+        return true;
+    }
+    
+    if (!TYPEINFO_IS_ARRAY(*srcarray)) {
+               /* XXX should we make that a verify error? */
+               exceptions_throw_internalerror("Trying to access component of non-array");
+               return false;
+       }
+
+       /* save the mergedlist (maybe dst == srcarray) */
+
+       merged = srcarray->merged;
+
+       if (IS_CLASSREF(srcarray->typeclass)) {
+               constant_classref *comp;
+               comp = class_get_classref_component_of(srcarray->typeclass.ref);
+
+               if (comp) {
+                       if (!typeinfo_init_class(dst,CLASSREF_OR_CLASSINFO(comp)))
+                               return false;
+               }
+               else {
+                       TYPEINFO_INIT_PRIMITIVE(*dst);
+               }
+       }
+       else {
+               vftbl_t *comp;
+               
+               if (!(srcarray->typeclass.cls->state & CLASS_LINKED)) {
+                       if (!link_class(srcarray->typeclass.cls)) {
+                               return false;
+                       }
+               }
+
+               TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl);
+               TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl->arraydesc);
+
+               comp = srcarray->typeclass.cls->vftbl->arraydesc->componentvftbl;
+               if (comp)
+                       typeinfo_init_classinfo(dst,comp->clazz);
+               else
+                       TYPEINFO_INIT_PRIMITIVE(*dst);
+       }
+    
+    dst->merged = merged; /* XXX should we do a deep copy? */
+       return true;
+}
+
+/* typeinfo_clone **************************************************************
+   Create a deep copy of a typeinfo struct.
+   
+   IN:
+          src..............the typeinfo to copy
+
+   OUT:
+       *dest............receives the copy
+
+   NOTE:
+       If src == dest this function is a nop.
+
+*******************************************************************************/
+
+void
+typeinfo_clone(typeinfo_t *src,typeinfo_t *dest)
+{
+    int count;
+    classref_or_classinfo *srclist,*destlist;
+
+    if (src == dest)
+        return;
+    
+    *dest = *src;
+
+    if (src->merged) {
+        count = src->merged->count;
+        TYPEINFO_ALLOCMERGED(dest->merged,count);
+        dest->merged->count = count;
+
+        srclist = src->merged->list;
+        destlist = dest->merged->list;
+        while (count--)
+            *destlist++ = *srclist++;
+    }
+}
+
+/**********************************************************************/
+/* MISCELLANEOUS FUNCTIONS                                            */
+/**********************************************************************/
+
+/* typeinfo_free ***************************************************************
+   Free memory referenced by the given typeinfo. The typeinfo itself is not
+   freed.
+   
+   IN:
+       info.............the typeinfo
+
+*******************************************************************************/
+
+void
+typeinfo_free(typeinfo_t *info)
+{
+    TYPEINFO_FREEMERGED_IF_ANY(info->merged);
+    info->merged = NULL;
+}
+
+/**********************************************************************/
+/* MERGING FUNCTIONS                                                  */
+/* The following functions are used to merge the types represented by */
+/* two typeinfo structures into one typeinfo structure.               */
+/**********************************************************************/
+
+static
+void
+typeinfo_merge_error(methodinfo *m,char *str,typeinfo_t *x,typeinfo_t *y) {
+#ifdef TYPEINFO_VERBOSE
+    fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
+    fprintf(stderr,"Typeinfo x:\n");
+    typeinfo_print(stderr,x,1);
+    fprintf(stderr,"Typeinfo y:\n");
+    typeinfo_print(stderr,y,1);
+    log_text(str);
+#endif
+
+       exceptions_throw_verifyerror(m, str);
+}
+
+/* Condition: clsx != clsy. */
+/* Returns: true if dest was changed (currently always true). */
+static
+bool
+typeinfo_merge_two(typeinfo_t *dest,classref_or_classinfo clsx,classref_or_classinfo clsy)
+{
+       TYPEINFO_ASSERT(dest);
+    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+    TYPEINFO_ALLOCMERGED(dest->merged,2);
+    dest->merged->count = 2;
+
+       TYPEINFO_ASSERT(clsx.any != clsy.any);
+
+    if (clsx.any < clsy.any) {
+        dest->merged->list[0] = clsx;
+        dest->merged->list[1] = clsy;
+    }
+    else {
+        dest->merged->list[0] = clsy;
+        dest->merged->list[1] = clsx;
+    }
+
+    return true;
+}
+
+/* Returns: true if dest was changed. */
+static
+bool
+typeinfo_merge_add(typeinfo_t *dest,typeinfo_mergedlist_t *m,classref_or_classinfo cls)
+{
+    int count;
+    typeinfo_mergedlist_t *newmerged;
+    classref_or_classinfo *mlist,*newlist;
+
+    count = m->count;
+    mlist = m->list;
+
+    /* Check if cls is already in the mergedlist m. */
+    while (count--) {
+        if ((mlist++)->any == cls.any) { /* XXX check equal classrefs? */
+            /* cls is in the list, so m is the resulting mergedlist */
+            if (dest->merged == m)
+                return false;
+
+            /* We have to copy the mergedlist */
+            TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+            count = m->count;
+            TYPEINFO_ALLOCMERGED(dest->merged,count);
+            dest->merged->count = count;
+            newlist = dest->merged->list;
+            mlist = m->list;
+            while (count--) {
+                *newlist++ = *mlist++;
+            }
+            return true;
+        }
+    }
+
+    /* Add cls to the mergedlist. */
+    count = m->count;
+    TYPEINFO_ALLOCMERGED(newmerged,count+1);
+    newmerged->count = count+1;
+    newlist = newmerged->list;    
+    mlist = m->list;
+    while (count) {
+        if (mlist->any > cls.any)
+            break;
+        *newlist++ = *mlist++;
+        count--;
+    }
+    *newlist++ = cls;
+    while (count--) {
+        *newlist++ = *mlist++;
+    }
+
+    /* Put the new mergedlist into dest. */
+    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+    dest->merged = newmerged;
+    
+    return true;
+}
+
+/* Returns: true if dest was changed. */
+static
+bool
+typeinfo_merge_mergedlists(typeinfo_t *dest,typeinfo_mergedlist_t *x,
+                           typeinfo_mergedlist_t *y)
+{
+    int count = 0;
+    int countx,county;
+    typeinfo_mergedlist_t *temp,*result;
+    classref_or_classinfo *clsx,*clsy,*newlist;
+
+    /* count the elements that will be in the resulting list */
+    /* (Both lists are sorted, equal elements are counted only once.) */
+    clsx = x->list;
+    clsy = y->list;
+    countx = x->count;
+    county = y->count;
+    while (countx && county) {
+        if (clsx->any == clsy->any) {
+            clsx++;
+            clsy++;
+            countx--;
+            county--;
+        }
+        else if (clsx->any < clsy->any) {
+            clsx++;
+            countx--;
+        }
+        else {
+            clsy++;
+            county--;
+        }
+        count++;
+    }
+    count += countx + county;
+
+    /* {The new mergedlist will have count entries.} */
+
+    if ((x->count != count) && (y->count == count)) {
+        temp = x; x = y; y = temp;
+    }
+    /* {If one of x,y is already the result it is x.} */
+    if (x->count == count) {
+        /* x->merged is equal to the result */
+        if (x == dest->merged)
+            return false;
+
+        if (!dest->merged || dest->merged->count != count) {
+            TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+            TYPEINFO_ALLOCMERGED(dest->merged,count);
+            dest->merged->count = count;
+        }
+
+        newlist = dest->merged->list;
+        clsx = x->list;
+        while (count--) {
+            *newlist++ = *clsx++;
+        }
+        return true;
+    }
+
+    /* {We have to merge two lists.} */
+
+    /* allocate the result list */
+    TYPEINFO_ALLOCMERGED(result,count);
+    result->count = count;
+    newlist = result->list;
+
+    /* merge the sorted lists */
+    clsx = x->list;
+    clsy = y->list;
+    countx = x->count;
+    county = y->count;
+    while (countx && county) {
+        if (clsx->any == clsy->any) {
+            *newlist++ = *clsx++;
+            clsy++;
+            countx--;
+            county--;
+        }
+        else if (clsx->any < clsy->any) {
+            *newlist++ = *clsx++;
+            countx--;
+        }
+        else {
+            *newlist++ = *clsy++;
+            county--;
+        }
+    }
+    while (countx--)
+            *newlist++ = *clsx++;
+    while (county--)
+            *newlist++ = *clsy++;
+
+    /* replace the list in dest with the result list */
+    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+    dest->merged = result;
+
+    return true;
+}
+
+/* typeinfo_merge_nonarrays ****************************************************
+   Merge two non-array types.
+   
+   IN:
+       x................the first type
+          y................the second type
+          mergedx..........merged list of the first type, may be NULL
+          mergedy..........merged list of the descond type, may be NULL
+
+   OUT:
+       *dest............receives the resulting merged list
+          *result..........receives the resulting type
+
+   RETURN VALUE:
+       typecheck_TRUE...*dest has been modified
+          typecheck_FALSE..*dest has not been modified
+          typecheck_FAIL...an exception has been thrown
+
+   NOTE:
+       RESULT is an extra parameter so it can point to dest->typeclass or to
+          dest->elementclass.
+
+*******************************************************************************/
+
+static typecheck_result
+typeinfo_merge_nonarrays(typeinfo_t *dest,
+                         classref_or_classinfo *result,
+                         classref_or_classinfo x,classref_or_classinfo y,
+                         typeinfo_mergedlist_t *mergedx,
+                         typeinfo_mergedlist_t *mergedy)
+{
+       classref_or_classinfo t;
+    classinfo *tcls,*common;
+    typeinfo_mergedlist_t *tmerged;
+    bool changed;
+       typecheck_result r;
+       utf *xname;
+       utf *yname;
+
+       TYPEINFO_ASSERT(dest && result && x.any && y.any);
+       TYPEINFO_ASSERT(x.cls != pseudo_class_Null);
+       TYPEINFO_ASSERT(y.cls != pseudo_class_Null);
+       TYPEINFO_ASSERT(x.cls != pseudo_class_New);
+       TYPEINFO_ASSERT(y.cls != pseudo_class_New);
+
+       /*--------------------------------------------------*/
+       /* common cases                                     */
+       /*--------------------------------------------------*/
+
+    /* Common case 1: x and y are the same class or class reference */
+    /* (This case is very simple unless *both* x and y really represent
+     *  merges of subclasses of clsx==clsy.)
+     */
+    if ( (x.any == y.any) && (!mergedx || !mergedy) ) {
+  return_simple_x:
+        /* DEBUG */ /* log_text("return simple x"); */
+        changed = (dest->merged != NULL);
+        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+        dest->merged = NULL;
+        *result = x;
+        /* DEBUG */ /* log_text("returning"); */
+        return (typecheck_result) changed;
+    }
+
+       xname = (IS_CLASSREF(x)) ? x.ref->name : x.cls->name;
+       yname = (IS_CLASSREF(y)) ? y.ref->name : y.cls->name;
+
+       /* Common case 2: xname == yname, at least one unresolved */
+    if ((IS_CLASSREF(x) || IS_CLASSREF(y)) && (xname == yname))
+       {
+               /* use the loaded one if any */
+               if (!IS_CLASSREF(y))
+                       x = y;
+               goto return_simple_x;
+    }
+
+       /*--------------------------------------------------*/
+       /* non-trivial cases                                */
+       /*--------------------------------------------------*/
+
+#ifdef TYPEINFO_VERBOSE
+       {
+               typeinfo_t dbgx,dbgy;
+               fprintf(stderr,"merge_nonarrays:\n");
+               fprintf(stderr,"    ");if(IS_CLASSREF(x))fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,xname);fprintf(stderr,"\n");
+               fprintf(stderr,"    ");if(IS_CLASSREF(y))fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,yname);fprintf(stderr,"\n");
+               fflush(stderr);
+               typeinfo_init_class(&dbgx,x);
+               dbgx.merged = mergedx;
+               typeinfo_init_class(&dbgy,y);
+               dbgy.merged = mergedy;
+               typeinfo_print(stderr,&dbgx,4);
+               fprintf(stderr,"  with:\n");
+               typeinfo_print(stderr,&dbgy,4);
+       }
+#endif
+
+       TYPEINFO_ASSERT(IS_CLASSREF(x) || (x.cls->state & CLASS_LOADED));
+       TYPEINFO_ASSERT(IS_CLASSREF(y) || (y.cls->state & CLASS_LOADED));
+
+    /* If y is unresolved or an interface, swap x and y. */
+    if (IS_CLASSREF(y) || (!IS_CLASSREF(x) && y.cls->flags & ACC_INTERFACE))
+       {
+        t = x; x = y; y = t;
+        tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
+    }
+       
+    /* {We know: If only one of x,y is unresolved it is x,} */
+    /* {         If both x,y are resolved and only one of x,y is an interface it is x.} */
+
+       if (IS_CLASSREF(x)) {
+               /* {We know: x and y have different class names} */
+               
+        /* Check if we are merging an unresolved type with java.lang.Object */
+        if (y.cls == class_java_lang_Object && !mergedy) {
+            x = y;
+            goto return_simple_x;
+        }
+            
+               common = class_java_lang_Object;
+               goto merge_with_simple_x;
+       }
+
+       /* {We know: both x and y are resolved} */
+    /* {We know: If only one of x,y is an interface it is x.} */
+
+       TYPEINFO_ASSERT(!IS_CLASSREF(x) && !IS_CLASSREF(y));
+       TYPEINFO_ASSERT(x.cls->state & CLASS_LOADED);
+       TYPEINFO_ASSERT(y.cls->state & CLASS_LOADED);
+
+    /* Handle merging of interfaces: */
+    if (x.cls->flags & ACC_INTERFACE) {
+        /* {x.cls is an interface and mergedx == NULL.} */
+        
+        if (y.cls->flags & ACC_INTERFACE) {
+            /* We are merging two interfaces. */
+            /* {mergedy == NULL} */
+
+            /* {We know that x.cls!=y.cls (see common case at beginning.)} */
+            result->cls = class_java_lang_Object;
+            return (typecheck_result) typeinfo_merge_two(dest,x,y);
+        }
+
+        /* {We know: x is an interface, y is a class.} */
+
+        /* Check if we are merging an interface with java.lang.Object */
+        if (y.cls == class_java_lang_Object && !mergedy) {
+            x = y;
+            goto return_simple_x;
+        }
+
+        /* If the type y implements x then the result of the merge
+         * is x regardless of mergedy.
+         */
+
+               /* we may have to link the classes */
+               if (!(x.cls->state & CLASS_LINKED))
+                       if (!link_class(x.cls))
+                               return typecheck_FAIL;
+               if (!(y.cls->state & CLASS_LINKED))
+                       if (!link_class(y.cls))
+                               return typecheck_FAIL;
+        
+               TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
+               TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
+
+        if (CLASSINFO_IMPLEMENTS_INTERFACE(y.cls,x.cls->index))
+               {
+            /* y implements x, so the result of the merge is x. */
+            goto return_simple_x;
+               }
+               
+        r = mergedlist_implements_interface(mergedy,x.cls);
+               if (r == typecheck_FAIL)
+                       return r;
+               if (r == typecheck_TRUE)
+        {
+            /* y implements x, so the result of the merge is x. */
+            goto return_simple_x;
+        }
+        
+        /* {We know: x is an interface, the type y a class or a merge
+         * of subclasses and is not guaranteed to implement x.} */
+
+        common = class_java_lang_Object;
+        goto merge_with_simple_x;
+    }
+
+    /* {We know: x and y are classes (not interfaces).} */
+    
+       /* we may have to link the classes */
+       if (!(x.cls->state & CLASS_LINKED))
+               if (!link_class(x.cls))
+                       return typecheck_FAIL;
+       if (!(y.cls->state & CLASS_LINKED))
+               if (!link_class(y.cls))
+                       return typecheck_FAIL;
+        
+       TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
+       TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
+
+    /* If *x is deeper in the inheritance hierarchy swap x and y. */
+    if (x.cls->index > y.cls->index) {
+        t = x; x = y; y = t;
+        tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
+    }
+
+    /* {We know: y is at least as deep in the hierarchy as x.} */
+
+    /* Find nearest common anchestor for the classes. */
+
+    common = x.cls;
+    tcls   = y.cls;
+
+    while (tcls->index > common->index)
+        tcls = tcls->super;
+
+    while (common != tcls) {
+        common = common->super;
+        tcls = tcls->super;
+    }
+
+    /* {common == nearest common anchestor of x and y.} */
+
+    /* If x.cls==common and x is a whole class (not a merge of subclasses)
+     * then the result of the merge is x.
+     */
+    if (x.cls == common && !mergedx) {
+        goto return_simple_x;
+    }
+   
+    if (mergedx) {
+        result->cls = common;
+        if (mergedy)
+            return (typecheck_result) typeinfo_merge_mergedlists(dest,mergedx,mergedy);
+        else
+            return (typecheck_result) typeinfo_merge_add(dest,mergedx,y);
+    }
+
+merge_with_simple_x:
+    result->cls = common;
+    if (mergedy)
+        return (typecheck_result) typeinfo_merge_add(dest,mergedy,x);
+    else
+        return (typecheck_result) typeinfo_merge_two(dest,x,y);
+}
+
+/* typeinfo_merge **************************************************************
+   Merge two types.
+   
+   IN:
+       m................method for exception messages
+       dest.............the first type
+       y................the second type
+
+   OUT:
+       *dest............receives the result of the merge
+
+   RETURN VALUE:
+       typecheck_TRUE...*dest has been modified
+       typecheck_FALSE..*dest has not been modified
+       typecheck_FAIL...an exception has been thrown
+
+   PRE-CONDITIONS:
+       1) *dest must be a valid initialized typeinfo
+       2) dest != y
+
+*******************************************************************************/
+
+typecheck_result
+typeinfo_merge(methodinfo *m,typeinfo_t *dest,typeinfo_t* y)
+{
+    typeinfo_t *x;
+    typeinfo_t *tmp;
+    classref_or_classinfo common;
+    classref_or_classinfo elementclass;
+    int dimension;
+    int elementtype;
+    bool changed;
+       typecheck_result r;
+
+       /*--------------------------------------------------*/
+       /* fast checks                                      */
+       /*--------------------------------------------------*/
+
+    /* Merging something with itself is a nop */
+    if (dest == y)
+        return typecheck_FALSE;
+
+    /* Merging two returnAddress types is ok. */
+       /* Merging two different returnAddresses never happens, as the verifier */
+       /* keeps them separate in order to check all the possible return paths  */
+       /* from JSR subroutines.                                                */
+    if (!dest->typeclass.any && !y->typeclass.any) {
+               TYPEINFO_ASSERT(TYPEINFO_RETURNADDRESS(*dest) ==  TYPEINFO_RETURNADDRESS(*y));
+        return typecheck_FALSE;
+       }
+    
+    /* Primitive types cannot be merged with reference types */
+       /* This must be checked before calls to typeinfo_merge.  */
+    TYPEINFO_ASSERT(dest->typeclass.any && y->typeclass.any);
+
+    /* handle uninitialized object types */
+    if (TYPEINFO_IS_NEWOBJECT(*dest) || TYPEINFO_IS_NEWOBJECT(*y)) {
+        if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y)) {
+            typeinfo_merge_error(m,(char*) "Trying to merge uninitialized object type.",dest,y);
+                       return typecheck_FAIL;
+               }
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest) != TYPEINFO_NEWOBJECT_INSTRUCTION(*y)) {
+            typeinfo_merge_error(m,(char*) "Trying to merge different uninitialized objects.",dest,y);
+                       return typecheck_FAIL;
+               }
+               /* the same uninitialized object -- no change */
+               return typecheck_FALSE;
+    }
+    
+       /*--------------------------------------------------*/
+       /* common cases                                     */
+       /*--------------------------------------------------*/
+
+    /* Common case: dest and y are the same class or class reference */
+    /* (This case is very simple unless *both* dest and y really represent
+     *  merges of subclasses of class dest==class y.)
+     */
+    if ((dest->typeclass.any == y->typeclass.any) && (!dest->merged || !y->merged)) {
+return_simple:
+        changed = (dest->merged != NULL);
+        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+        dest->merged = NULL;
+        return (typecheck_result) changed;
+    }
+    
+    /* Handle null types: */
+    if (TYPEINFO_IS_NULLTYPE(*y)) {
+        return typecheck_FALSE;
+    }
+    if (TYPEINFO_IS_NULLTYPE(*dest)) {
+        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+        TYPEINFO_CLONE(*y,*dest);
+        return typecheck_TRUE;
+    }
+
+       /* Common case: two types with the same name, at least one unresolved */
+       if (IS_CLASSREF(dest->typeclass)) {
+               if (IS_CLASSREF(y->typeclass)) {
+                       if (dest->typeclass.ref->name == y->typeclass.ref->name)
+                               goto return_simple;
+               }
+               else {
+                       /* XXX should we take y instead of dest here? */
+                       if (dest->typeclass.ref->name == y->typeclass.cls->name)
+                               goto return_simple;
+               }
+       }
+       else {
+               if (IS_CLASSREF(y->typeclass) 
+                   && (dest->typeclass.cls->name == y->typeclass.ref->name))
+               {
+                       goto return_simple;
+               }
+       }
+
+       /*--------------------------------------------------*/
+       /* non-trivial cases                                */
+       /*--------------------------------------------------*/
+
+#ifdef TYPEINFO_VERBOSE
+       fprintf(stderr,"merge:\n");
+    typeinfo_print(stderr,dest,4);
+    typeinfo_print(stderr,y,4);
+#endif
+
+    /* This function uses x internally, so x and y can be swapped
+     * without changing dest. */
+    x = dest;
+    changed = false;
+    
+    /* Handle merging of arrays: */
+    if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
+        
+        /* Make x the one with lesser dimension */
+        if (x->dimension > y->dimension) {
+            tmp = x; x = y; y = tmp;
+        }
+
+        /* If one array (y) has higher dimension than the other,
+         * interpret it as an array (same dim. as x) of Arraystubs. */
+        if (x->dimension < y->dimension) {
+            dimension = x->dimension;
+            elementtype = ARRAYTYPE_OBJECT;
+            elementclass.cls = pseudo_class_Arraystub;
+        }
+        else {
+            dimension = y->dimension;
+            elementtype = y->elementtype;
+            elementclass = y->elementclass;
+        }
+        
+        /* {The arrays are of the same dimension.} */
+        
+        if (x->elementtype != elementtype) {
+            /* Different element types are merged, so the resulting array
+             * type has one accessible dimension less. */
+            if (--dimension == 0) {
+                common.cls = pseudo_class_Arraystub;
+                elementtype = 0;
+                elementclass.any = NULL;
+            }
+            else {
+                common.cls = class_multiarray_of(dimension,pseudo_class_Arraystub,true);
+                               if (!common.cls) {
+                                       exceptions_throw_internalerror("XXX Coult not create array class");
+                                       return typecheck_FAIL;
+                               }
+
+                elementtype = ARRAYTYPE_OBJECT;
+                elementclass.cls = pseudo_class_Arraystub;
+            }
+        }
+        else {
+            /* {The arrays have the same dimension and elementtype.} */
+
+            if (elementtype == ARRAYTYPE_OBJECT) {
+                /* The elements are references, so their respective
+                 * types must be merged.
+                 */
+                               r = typeinfo_merge_nonarrays(dest,
+                                               &elementclass,
+                                               x->elementclass,
+                                               elementclass,
+                                               x->merged,y->merged);
+                               TYPEINFO_ASSERT(r != typecheck_MAYBE);
+                               if (r == typecheck_FAIL)
+                                       return r;
+                               changed |= r;
+
+                /* DEBUG */ /* log_text("finding resulting array class: "); */
+                               if (IS_CLASSREF(elementclass))
+                                       common.ref = class_get_classref_multiarray_of(dimension,elementclass.ref);
+                               else {
+                                       common.cls = class_multiarray_of(dimension,elementclass.cls,true);
+                                       if (!common.cls) {
+                                               exceptions_throw_internalerror("XXX Coult not create array class");
+                                               return typecheck_FAIL;
+                                       }
+                               }
+                /* DEBUG */ /* utf_display_printable_ascii(common->name); printf("\n"); */
+            }
+                       else {
+                               common.any = y->typeclass.any;
+                       }
+        }
+    }
+    else {
+        /* {We know that at least one of x or y is no array, so the
+         *  result cannot be an array.} */
+        
+               r = typeinfo_merge_nonarrays(dest,
+                               &common,
+                               x->typeclass,y->typeclass,
+                               x->merged,y->merged);
+               TYPEINFO_ASSERT(r != typecheck_MAYBE);
+               if (r == typecheck_FAIL)
+                       return r;
+               changed |= r;
+
+        dimension = 0;
+        elementtype = 0;
+        elementclass.any = NULL;
+    }
+
+    /* Put the new values into dest if neccessary. */
+
+    if (dest->typeclass.any != common.any) {
+        dest->typeclass.any = common.any;
+        changed = true;
+    }
+    if (dest->dimension != dimension) {
+        dest->dimension = dimension;
+        changed = true;
+    }
+    if (dest->elementtype != elementtype) {
+        dest->elementtype = elementtype;
+        changed = true;
+    }
+    if (dest->elementclass.any != elementclass.any) {
+        dest->elementclass.any = elementclass.any;
+        changed = true;
+    }
+
+    return (typecheck_result) changed;
+}
+#endif /* ENABLE_VERIFER */
+
+
+/**********************************************************************/
+/* DEBUGGING HELPERS                                                  */
+/**********************************************************************/
+
+#ifdef TYPEINFO_DEBUG
+
+#if 0
+static int
+typeinfo_test_compare(classref_or_classinfo *a,classref_or_classinfo *b)
+{
+    if (a->any == b->any) return 0;
+    if (a->any < b->any) return -1;
+    return +1;
+}
+
+static void
+typeinfo_test_parse(typeinfo_t *info,char *str)
+{
+    int num;
+    int i;
+    typeinfo_t *infobuf;
+    u1 *typebuf;
+    int returntype;
+    utf *desc = utf_new_char(str);
+    
+    num = typeinfo_count_method_args(desc,false);
+    if (num) {
+        typebuf = (u1*) DumpMemory::allocate(sizeof(u1) * num);
+        infobuf = (typeinfo_t*) DumpMemory::allocate(sizeof(typeinfo_t) * num);
+        
+        typeinfo_init_from_method_args(desc,typebuf,infobuf,num,false,
+                                       &returntype,info);
+
+        TYPEINFO_ALLOCMERGED(info->merged,num);
+        info->merged->count = num;
+
+        for (i=0; i<num; ++i) {
+            if (typebuf[i] != TYPE_ADR) {
+                log_text("non-reference type in mergedlist");
+                               assert(0);
+                       }
+
+            info->merged->list[i].any = infobuf[i].typeclass.any;
+        }
+        qsort(info->merged->list,num,sizeof(classref_or_classinfo),
+              (int(*)(const void *,const void *))&typeinfo_test_compare);
+    }
+    else {
+        typeinfo_init_from_method_args(desc,NULL,NULL,0,false,
+                                       &returntype,info);
+    }
+}
+#endif
+
+#define TYPEINFO_TEST_BUFLEN  4000
+
+static bool
+typeinfo_equal(typeinfo_t *x,typeinfo_t *y)
+{
+    int i;
+    
+    if (x->typeclass.any != y->typeclass.any) return false;
+    if (x->dimension != y->dimension) return false;
+    if (x->dimension) {
+        if (x->elementclass.any != y->elementclass.any) return false;
+        if (x->elementtype != y->elementtype) return false;
+    }
+
+    if (TYPEINFO_IS_NEWOBJECT(*x))
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*x)
+            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+            return false;
+
+    if (x->merged || y->merged) {
+        if (!(x->merged && y->merged)) return false;
+        if (x->merged->count != y->merged->count) return false;
+        for (i=0; i<x->merged->count; ++i)
+            if (x->merged->list[i].any != y->merged->list[i].any)
+                return false;
+    }
+    return true;
+}
+
+static void
+typeinfo_testmerge(typeinfo_t *a,typeinfo_t *b,typeinfo_t *result,int *failed)
+{
+    typeinfo_t dest;
+    bool changed,changed_should_be;
+       typecheck_result r;
+
+    TYPEINFO_CLONE(*a,dest);
+    
+    printf("\n          ");
+    typeinfo_print_short(stdout,&dest);
+    printf("\n          ");
+    typeinfo_print_short(stdout,b);
+    printf("\n");
+
+       r = typeinfo_merge(NULL,&dest,b);
+       if (r == typecheck_FAIL) {
+               printf("EXCEPTION\n");
+               return;
+       }
+    changed = (r) ? 1 : 0;
+    changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0;
+
+    printf("          %s\n",(changed) ? "changed" : "=");
+
+    if (typeinfo_equal(&dest,result)) {
+        printf("OK        ");
+        typeinfo_print_short(stdout,&dest);
+        printf("\n");
+        if (changed != changed_should_be) {
+            printf("WRONG RETURN VALUE!\n");
+            (*failed)++;
+        }
+    }
+    else {
+        printf("RESULT    ");
+        typeinfo_print_short(stdout,&dest);
+        printf("\n");
+        printf("SHOULD BE ");
+        typeinfo_print_short(stdout,result);
+        printf("\n");
+        (*failed)++;
+    }
+}
+
+#if 0
+static void
+typeinfo_inc_dimension(typeinfo_t *info)
+{
+    if (info->dimension++ == 0) {
+        info->elementtype = ARRAYTYPE_OBJECT;
+        info->elementclass = info->typeclass;
+    }
+    info->typeclass = class_array_of(info->typeclass,true);
+}
+#endif
+
+#define TYPEINFO_TEST_MAXDIM  10
+
+static void
+typeinfo_testrun(char *filename)
+{
+    char buf[TYPEINFO_TEST_BUFLEN];
+    char bufa[TYPEINFO_TEST_BUFLEN];
+    char bufb[TYPEINFO_TEST_BUFLEN];
+    char bufc[TYPEINFO_TEST_BUFLEN];
+    typeinfo_t a,b,c;
+    int maxdim;
+    int failed = 0;
+    FILE *file = fopen(filename,"rt");
+       int res;
+    
+    if (!file) {
+        log_text("could not open typeinfo test file");
+               assert(0);
+       }
+
+    while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) {
+        if (buf[0] == '#' || !strlen(buf))
+            continue;
+        
+        res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
+        if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc)) {
+            log_text("Invalid line in typeinfo test file (none of empty, comment or test)");
+                       assert(0);
+               }
+
+#if 0
+        typeinfo_test_parse(&a,bufa);
+        typeinfo_test_parse(&b,bufb);
+        typeinfo_test_parse(&c,bufc);
+#endif
+#if 0
+        do {
+#endif
+            typeinfo_testmerge(&a,&b,&c,&failed); /* check result */
+            typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */
+
+            if (TYPEINFO_IS_NULLTYPE(a)) break;
+            if (TYPEINFO_IS_NULLTYPE(b)) break;
+            if (TYPEINFO_IS_NULLTYPE(c)) break;
+            
+            maxdim = a.dimension;
+            if (b.dimension > maxdim) maxdim = b.dimension;
+            if (c.dimension > maxdim) maxdim = c.dimension;
+
+#if 0
+            if (maxdim < TYPEINFO_TEST_MAXDIM) {
+                typeinfo_inc_dimension(&a);
+                typeinfo_inc_dimension(&b);
+                typeinfo_inc_dimension(&c);
+            }
+        } while (maxdim < TYPEINFO_TEST_MAXDIM);
+#endif
+    }
+
+    fclose(file);
+
+    if (failed) {
+        fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed);
+        log_text("Failed test");
+               assert(0);
+    }
+}
+
+void
+typeinfo_test()
+{
+    log_text("Running typeinfo test file...");
+    typeinfo_testrun("typeinfo.tst");
+    log_text("Finished typeinfo test file.");
+}
+
+#if 0
+void
+typeinfo_init_from_fielddescriptor(typeinfo_t *info,char *desc)
+{
+    typeinfo_init_from_descriptor(info,desc,desc+strlen(desc));
+}
+#endif
+
+#define TYPEINFO_MAXINDENT  80
+
+void
+typeinfo_print_class(FILE *file,classref_or_classinfo c)
+{
+       /*fprintf(file,"<class %p>",c.any);*/
+
+       if (!c.any) {
+               fprintf(file,"<null>");
+       }
+       else {
+               if (IS_CLASSREF(c)) {
+                       fprintf(file,"<ref>");
+                       utf_fprint_printable_ascii(file,c.ref->name);
+               }
+               else {
+                       utf_fprint_printable_ascii(file,c.cls->name);
+               }
+       }
+}
+
+void
+typeinfo_print(FILE *file,typeinfo_t *info,int indent)
+{
+    int i;
+    char ind[TYPEINFO_MAXINDENT + 1];
+    instruction *ins;
+       basicblock *bptr;
+
+    if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
+    
+    for (i=0; i<indent; ++i)
+        ind[i] = ' ';
+    ind[i] = (char) 0;
+    
+    if (TYPEINFO_IS_PRIMITIVE(*info)) {
+               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+               if (bptr)
+                       fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->nr);
+               else
+                       fprintf(file,"%sprimitive\n",ind);
+        return;
+    }
+    
+    if (TYPEINFO_IS_NULLTYPE(*info)) {
+        fprintf(file,"%snull\n",ind);
+        return;
+    }
+
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+            fprintf(file,"%sNEW(%p):",ind,(void*)ins);
+                       typeinfo_print_class(file,ins[-1].sx.val.c);
+            fprintf(file,"\n");
+        }
+        else {
+            fprintf(file,"%sNEW(this)",ind);
+        }
+        return;
+    }
+
+    fprintf(file,"%sClass:      ",ind);
+       typeinfo_print_class(file,info->typeclass);
+    fprintf(file,"\n");
+
+    if (TYPEINFO_IS_ARRAY(*info)) {
+        fprintf(file,"%sDimension:    %d",ind,(int)info->dimension);
+        fprintf(file,"\n%sElements:     ",ind);
+        switch (info->elementtype) {
+          case ARRAYTYPE_INT     : fprintf(file,"int\n"); break;
+          case ARRAYTYPE_LONG    : fprintf(file,"long\n"); break;
+          case ARRAYTYPE_FLOAT   : fprintf(file,"float\n"); break;
+          case ARRAYTYPE_DOUBLE  : fprintf(file,"double\n"); break;
+          case ARRAYTYPE_BYTE    : fprintf(file,"byte\n"); break;
+          case ARRAYTYPE_CHAR    : fprintf(file,"char\n"); break;
+          case ARRAYTYPE_SHORT   : fprintf(file,"short\n"); break;
+          case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break;
+              
+          case ARRAYTYPE_OBJECT:
+                         typeinfo_print_class(file,info->elementclass);
+              fprintf(file,"\n");
+              break;
+              
+          default:
+              fprintf(file,"INVALID ARRAYTYPE!\n");
+        }
+    }
+
+    if (info->merged) {
+        fprintf(file,"%sMerged:     ",ind);
+        for (i=0; i<info->merged->count; ++i) {
+            if (i) fprintf(file,", ");
+                       typeinfo_print_class(file,info->merged->list[i]);
+        }
+        fprintf(file,"\n");
+    }
+}
+
+void
+typeinfo_print_short(FILE *file,typeinfo_t *info)
+{
+    int i;
+    instruction *ins;
+       basicblock *bptr;
+
+       /*fprintf(file,"<typeinfo %p>",info);*/
+
+       if (!info) {
+               fprintf(file,"(typeinfo*)NULL");
+               return;
+       }
+
+    if (TYPEINFO_IS_PRIMITIVE(*info)) {
+               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+               if (bptr)
+                       fprintf(file,"ret(L%03d)",bptr->nr);
+               else
+                       fprintf(file,"primitive");
+        return;
+    }
+    
+    if (TYPEINFO_IS_NULLTYPE(*info)) {
+        fprintf(file,"null");
+        return;
+    }
+    
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+                       /*fprintf(file,"<ins %p>",ins);*/
+            fprintf(file,"NEW(%p):",(void*)ins);
+                       typeinfo_print_class(file,ins[-1].sx.val.c);
+        }
+        else
+            fprintf(file,"NEW(this)");
+        return;
+    }
+
+    typeinfo_print_class(file,info->typeclass);
+
+    if (info->merged) {
+        fprintf(file,"{");
+        for (i=0; i<info->merged->count; ++i) {
+            if (i) fprintf(file,",");
+                       typeinfo_print_class(file,info->merged->list[i]);
+        }
+        fprintf(file,"}");
+    }
+}
+
+void
+typeinfo_print_type(FILE *file,int type,typeinfo_t *info)
+{
+    switch (type) {
+      case TYPE_VOID: fprintf(file,"V"); break;
+      case TYPE_INT:  fprintf(file,"I"); break;
+      case TYPE_FLT:  fprintf(file,"F"); break;
+      case TYPE_DBL:  fprintf(file,"D"); break;
+      case TYPE_LNG:  fprintf(file,"J"); break;
+         case TYPE_RET:  fprintf(file,"R:"); /* FALLTHROUGH! */
+      case TYPE_ADR:
+                 typeinfo_print_short(file,info);
+          break;
+          
+      default:
+          fprintf(file,"!");
+    }
+}
+
+void
+typedescriptor_print(FILE *file,typedescriptor_t *td)
+{
+       typeinfo_print_type(file,td->type,&(td->typeinfo));
+}
+
+void
+typevector_print(FILE *file,varinfo *vec,int size)
+{
+    int i;
+
+    for (i=0; i<size; ++i) {
+               fprintf(file," %d=",i);
+        typeinfo_print_type(file, vec[i].type, &(vec[i].typeinfo));
+    }
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* TYPEINFO_DEBUG */
+
+
+/*
+ * 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/jit/verify/typeinfo.h b/src/vm/jit/verify/typeinfo.h
deleted file mode 100644 (file)
index 806bca9..0000000
+++ /dev/null
@@ -1,539 +0,0 @@
-/* src/vm/jit/verify/typeinfo.h - type system used by the type checker
-
-   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 _TYPEINFO_H
-#define _TYPEINFO_H
-
-/* resolve typedef cycles *****************************************************/
-
-typedef struct typeinfo            typeinfo_t;
-typedef struct typeinfo_mergedlist typeinfo_mergedlist_t;
-typedef struct typedescriptor      typedescriptor_t;
-
-#include "config.h"
-#include "vm/types.h"
-
-#include "vm/global.h"
-#include "vm/references.h"
-
-
-/* configuration **************************************************************/
-
-/*
- * TYPECHECK_STATISTICS activates gathering statistical information.
- * TYPEINFO_DEBUG activates debug checks and debug helpers in typeinfo.c
- * TYPECHECK_DEBUG activates debug checks in typecheck.c
- * TYPEINFO_DEBUG_TEST activates the typeinfo test at startup.
- * TYPECHECK_VERBOSE_IMPORTANT activates important debug messages
- * TYPECHECK_VERBOSE activates all debug messages
- * TYPEINFO_VERBOSE activates debug prints in typeinfo.c
- */
-#ifdef ENABLE_VERIFIER
-#ifndef NDEBUG
-/*#define TYPECHECK_STATISTICS*/
-#define TYPEINFO_DEBUG
-/*#define TYPEINFO_VERBOSE*/
-#define TYPECHECK_DEBUG
-/*#define TYPEINFO_DEBUG_TEST*/
-/*#define TYPECHECK_VERBOSE*/
-/*#define TYPECHECK_VERBOSE_IMPORTANT*/
-#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
-#define TYPECHECK_VERBOSE_OPT
-#endif
-#endif
-#endif
-
-#ifdef TYPECHECK_VERBOSE_OPT
-extern bool opt_typecheckverbose;
-#endif
-
-/* types **********************************************************************/
-
-/* typecheck_result - return type for boolean and tristate  functions     */
-/*                    which may also throw exceptions (typecheck_FAIL).   */
-
-/* NOTE: Use the enum values, not the uppercase #define macros!          */
-#define TYPECHECK_MAYBE  0x02
-#define TYPECHECK_FAIL   0x04
-
-typedef enum {
-       typecheck_FALSE = false,
-       typecheck_TRUE  = true,
-       typecheck_MAYBE = TYPECHECK_MAYBE,
-       typecheck_FAIL  = TYPECHECK_FAIL
-} typecheck_result;
-
-/* check that typecheck_MAYBE is not ambiguous */
-#if TYPECHECK_MAYBE == true
-#error "`typecheck_MAYBE` must not be the same as `true`"
-#endif
-#if TYPECHECK_MAYBE == false
-#error "`typecheck_MAYBE` must not be the same as `false`"
-#endif
-
-/* check that typecheck_FAIL is not ambiguous */
-#if (true & TYPECHECK_FAIL) != 0
-#error "`true` must not have bit 0x02 set (conflicts with typecheck_FAIL)"
-#endif
-
-/* data structures for the type system ****************************************/
-
-/* The typeinfo structure stores detailed information on address types.
- * (stack elements, variables, etc. with type == TYPE_ADR.)
- *
- * There are two kinds of address types which can be distinguished by
- * the value of the typeclass field:
- *
- * 1) typeclass == NULL: returnAddress type
- *                       use TYPEINFO_IS_PRIMITIVE to test for this
- *
- * 2) typeclass != NULL: reference type
- *                       use TYPEINFO_IS_REFERENCE to test for this
- *
- * Note: For non-address types either there is no typeinfo allocated
- * or the fields of the typeinfo struct contain undefined values!
- * DO NOT access the typeinfo for non-address types!
- *
- * CAUTION: The typeinfo structure should be considered opaque outside of
- *          typeinfo.[ch]. Please use the macros and functions defined here to
- *          access typeinfo structures!
- */
-
-/* At all times *exactly one* of the following conditions is true for
- * a particular typeinfo struct:
- *
- * A) typeclass == NULL
- *
- *        This is a returnAddress type.
- *
- *        Use TYPEINFO_IS_PRIMITIVE to check for this.
- *        Use TYPEINFO_RETURNADDRESS to access the pointer in elementclass.
- *        Don't access other fields of the struct.
- *
- * B) typeclass == pseudo_class_Null
- *
- *        This is the null-reference type. 
- *        Use TYPEINFO_IS_NULLTYPE to check for this.
- *        Don't access other fields of the struct.
- *
- * C) typeclass == pseudo_class_New
- *
- *        This is an 'uninitialized object' type. elementclass can be
- *        cast to instruction* and points to the NEW instruction
- *        responsible for creating this type.
- *
- *        Use TYPEINFO_NEWOBJECT_INSTRUCTION to access the pointer in
- *        elementclass.
- *        Don't access other fields of the struct.
- *
- * D) typeclass == pseudo_class_Arraystub
- *
- *        This type is used to represent the result of merging array types
- *        with incompatible component types. An arraystub allows no access
- *        to its components (since their type is undefined), but it allows
- *        operations which act directly on an arbitrary array type (such as
- *        requesting the array size).
- *
- *        NOTE: An array stub does *not* count as an array. It has dimension
- *              zero.
- *
- *        Otherwise like a normal class reference type.
- *        Don't access other fields of the struct.
- *
- * E) typeclass is an array class
- *
- *        An array reference.
- *            elementclass...typeclass of the element type
- *            dimension......dimension of the array (>=1)
- *            elementtype....element type (ARRAYTYPE_...)
- *            merged.........mergedlist of the element type
- *
- *        Use TYPEINFO_IS_ARRAY to check for this case.
- *
- *        The elementclass may be one of the following:
- *        1) pseudo_class_Arraystub
- *        2) an unresolved type
- *        3) a loaded interface
- *        4) a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
- *                Note: `merged` may be used
- *        5) (BOOTSTRAP)java.lang.Object
- *                Note: `merged` may be used
- *
- *        For the semantics of the merged field in cases 4) and 5) consult the 
- *        corresponding descriptions with `elementclass` replaced by `typeclass`.
- *
- * F) typeclass is an unresolved type (a symbolic class/interface reference)
- *
- *        The type has not been resolved yet. (Meaning it corresponds to an
- *        unloaded class or interface).
- *        Don't access other fields of the struct.
- *
- * G) typeclass is a loaded interface
- *
- *        An interface reference type.
- *        Don't access other fields of the struct.
- *
- * H) typeclass is a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
- *
- *        A loaded class type.
- *        All classref_or_classinfos in u.merged.list (if any) are
- *        loaded subclasses of typeclass (no interfaces, array classes, or
- *        unresolved types).
- *        Don't access other fields of the struct.
- *
- * I) typeclass is (BOOTSTRAP)java.lang.Object
- *
- *        The most general kind of reference type.
- *        In this case u.merged.count and u.merged.list
- *        are valid and may be non-zero.
- *        The classref_or_classinfos in u.merged.list (if any) may be
- *        classes, interfaces, pseudo classes or unresolved types.
- *        Don't access other fields of the struct.
- */
-
-/* The following algorithm is used to determine if the type described
- * by this typeinfo struct supports the interface X:  * XXX add MAYBE *
- *
- *     1) If typeclass is X or a subinterface of X the answer is "yes".
- *     2) If typeclass is a (pseudo) class implementing X the answer is "yes".
- *     3) If typeclass is not an array and u.merged.count>0
- *        and all classes/interfaces in u.merged.list implement X
- *        the answer is "yes".
- *     4) If none of the above is true the answer is "no".
- */
-
-/*
- * CAUTION: The typeinfo structure should be considered opaque outside of
- *          typeinfo.[ch]. Please use the macros and functions defined here to
- *          access typeinfo structures!
- */
-struct typeinfo {
-       classref_or_classinfo  typeclass;
-       classref_or_classinfo  elementclass; /* valid if dimension>0 */ /* various uses! */
-       typeinfo_mergedlist_t *merged;
-       u1                     dimension;
-       u1                     elementtype;  /* valid if dimension>0           */
-};
-
-struct typeinfo_mergedlist {
-       s4                    count;
-       classref_or_classinfo list[1];       /* variable length!                        */
-};
-
-/* a type descriptor stores a basic type and the typeinfo                */
-/* this is used for storing the type of a local variable, and for        */
-/* storing types in the signature of a method                            */
-
-struct typedescriptor {
-       typeinfo_t      typeinfo; /* valid if type == TYPE_ADR               */
-       u1              type;     /* basic type (TYPE_INT, ...)              */
-};
-
-/****************************************************************************/
-/* MACROS                                                                   */
-/****************************************************************************/
-
-/* NOTE: The TYPEINFO macros take typeinfo *structs*, not pointers as
- *       arguments.  You have to dereference any pointers.
- */
-
-/* typevectors **************************************************************/
-
-#define TYPEVECTOR_SIZE(size)                                          \
-    ((size) * sizeof(varinfo)) 
-
-#define DNEW_TYPEVECTOR(size)                                          \
-    ((varinfo *) DMNEW(uint8_t, TYPEVECTOR_SIZE(size)))
-
-#define DMNEW_TYPEVECTOR(num,size)                                             \
-    ((void *) DMNEW(uint8_t, (num) * TYPEVECTOR_SIZE(size)))
-
-#define MGET_TYPEVECTOR(array,index,size) \
-    ((varinfo*) (((u1*)(array)) + TYPEVECTOR_SIZE(size) * (index)))
-
-/* internally used macros ***************************************************/
-
-/* internal, don't use this explicitly! */
-#define TYPEINFO_ALLOCMERGED(mergedlist,count)                                 \
-    do {(mergedlist) = (typeinfo_mergedlist_t *) DMNEW(uint8_t,        \
-            sizeof(typeinfo_mergedlist_t)                       \
-            + ((count)-1)*sizeof(classinfo*));} while(0)
-
-/* internal, don't use this explicitly! */
-#define TYPEINFO_FREEMERGED(mergedlist)
-
-/* internal, don't use this explicitly! */
-#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
-
-/* macros for type queries **************************************************/
-
-#define TYPEINFO_IS_PRIMITIVE(info)                             \
-            ((info).typeclass.any == NULL)
-
-#define TYPEINFO_IS_REFERENCE(info)                             \
-            ((info).typeclass.any != NULL)
-
-#define TYPEINFO_IS_NULLTYPE(info)                              \
-            ((info).typeclass.cls == pseudo_class_Null)
-
-#define TYPEINFO_IS_NEWOBJECT(info)                             \
-            ((info).typeclass.cls == pseudo_class_New)
-
-#define TYPEINFO_IS_JAVA_LANG_CLASS(info)                       \
-            ((info).typeclass.cls == class_java_lang_Class)
-
-/* only use this if TYPEINFO_IS_PRIMITIVE returned true! */
-#define TYPEINFO_RETURNADDRESS(info)                            \
-            ((info).elementclass.any)
-
-/* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
-#define TYPEINFO_NEWOBJECT_INSTRUCTION(info)                    \
-               ((info).elementclass.any)
-
-/* only use this if TYPEINFO_IS_JAVA_LANG_CLASS returned true! */
-#define TYPEINFO_JAVA_LANG_CLASS_CLASSREF(info)                 \
-               ((info).elementclass.ref)
-
-/* macros for array type queries ********************************************/
-
-#define TYPEINFO_IS_ARRAY(info)                                 \
-            ( TYPEINFO_IS_REFERENCE(info)                       \
-              && ((info).dimension != 0) )
-
-#define TYPEINFO_IS_SIMPLE_ARRAY(info)                          \
-            ( ((info).dimension == 1) )
-
-#define TYPEINFO_IS_ARRAY_ARRAY(info)                           \
-            ( ((info).dimension >= 2) )
-
-#define TYPEINFO_IS_PRIMITIVE_ARRAY(info,arraytype)             \
-            ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
-              && ((info).elementtype == (arraytype)) )
-
-#define TYPEINFO_IS_OBJECT_ARRAY(info)                          \
-            ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
-              && ((info).elementclass.any != NULL) )
-
-/* assumes that info describes an array type */
-#define TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info)                 \
-            ( ((info).elementclass.any != NULL)                 \
-              || ((info).dimension >= 2) )
-
-#define TYPEINFO_IS_ARRAY_OF_REFS(info)                         \
-            ( TYPEINFO_IS_ARRAY(info)                           \
-              && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
-
-#define TYPE_IS_RETURNADDRESS(type,info)                        \
-            ( ((type)==TYPE_RET)                                \
-              && TYPEINFO_IS_PRIMITIVE(info) )
-
-#define TYPE_IS_REFERENCE(type,info)                            \
-            ( ((type)==TYPE_ADR)                                \
-              && !TYPEINFO_IS_PRIMITIVE(info) )
-
-#define TYPEDESC_IS_RETURNADDRESS(td)                           \
-            TYPE_IS_RETURNADDRESS((td).type,(td).typeinfo)
-
-#define TYPEDESC_IS_REFERENCE(td)                               \
-            TYPE_IS_REFERENCE((td).type,(td).typeinfo)
-
-/* queries allowing the null type ********************************************/
-
-#define TYPEINFO_MAYBE_ARRAY(info)                              \
-    (TYPEINFO_IS_ARRAY(info) || TYPEINFO_IS_NULLTYPE(info))
-
-#define TYPEINFO_MAYBE_PRIMITIVE_ARRAY(info,at)                 \
-    (TYPEINFO_IS_PRIMITIVE_ARRAY(info,at) || TYPEINFO_IS_NULLTYPE(info))
-
-#define TYPEINFO_MAYBE_ARRAY_OF_REFS(info)                      \
-    (TYPEINFO_IS_ARRAY_OF_REFS(info) || TYPEINFO_IS_NULLTYPE(info))
-
-/* macros for initializing typeinfo structures ******************************/
-
-#define TYPEINFO_INIT_PRIMITIVE(info)                           \
-         do {(info).typeclass.any = NULL;                       \
-             (info).elementclass.any = NULL;                    \
-             (info).merged = NULL;                              \
-             (info).dimension = 0;                              \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_RETURNADDRESS(info,adr)                   \
-         do {(info).typeclass.any = NULL;                       \
-             (info).elementclass.any = (adr);                   \
-             (info).merged = NULL;                              \
-             (info).dimension = 0;                              \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo)   \
-         do {(info).typeclass.cls = (cinfo);            \
-             (info).elementclass.any = NULL;            \
-             (info).merged = NULL;                      \
-             (info).dimension = 0;                      \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_JAVA_LANG_CLASS(info,c)                   \
-         do {(info).typeclass.any = class_java_lang_Class;      \
-             (info).elementclass = (c);                         \
-             (info).merged = NULL;                              \
-             (info).dimension = 0;                              \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_NULLTYPE(info)                            \
-            TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,pseudo_class_Null)
-
-#define TYPEINFO_INIT_NEWOBJECT(info,instr)             \
-         do {(info).typeclass.cls = pseudo_class_New;   \
-             (info).elementclass.any = (instr);         \
-             (info).merged = NULL;                      \
-             (info).dimension = 0;                      \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_PRIMITIVE_ARRAY(info,arraytype)                   \
-    typeinfo_init_classinfo(&(info),primitivetype_table[arraytype].arrayclass);
-
-/* macros for copying types (destinition is not checked or freed) ***********/
-
-/* TYPEINFO_COPY makes a shallow copy, the merged pointer is simply copied. */
-#define TYPEINFO_COPY(src,dst)                                  \
-    do {(dst) = (src);} while(0)
-
-/* TYPEINFO_CLONE makes a deep copy, the merged list (if any) is duplicated
- * into a newly allocated array.
- */
-#define TYPEINFO_CLONE(src,dst)                                 \
-    do {(dst) = (src);                                          \
-        if ((dst).merged) typeinfo_clone(&(src),&(dst));} while(0)
-
-/****************************************************************************/
-/* FUNCTIONS                                                                */
-/****************************************************************************/
-
-#ifdef __cplusplus
-extern "C" { 
-#endif
-
-/* typevector functions *****************************************************/
-
-/* element read-only access */
-bool typevector_checktype(varinfo *set,int index,int type);
-bool typevector_checkreference(varinfo *set,int index);
-bool typevector_checkretaddr(varinfo *set,int index);
-
-/* element write access */
-void typevector_store(varinfo *set,int index,int type,typeinfo_t *info);
-void typevector_store_retaddr(varinfo *set,int index,typeinfo_t *info);
-bool typevector_init_object(varinfo *set,void *ins,classref_or_classinfo initclass,int size);
-
-/* vector functions */
-varinfo *typevector_copy(varinfo *src,int size);
-void typevector_copy_inplace(varinfo *src,varinfo *dst,int size);
-typecheck_result typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size);
-
-/* inquiry functions (read-only) ********************************************/
-
-bool typeinfo_is_array(typeinfo_t *info);
-bool typeinfo_is_primitive_array(typeinfo_t *info,int arraytype);
-bool typeinfo_is_array_of_refs(typeinfo_t *info);
-
-typecheck_result typeinfo_is_assignable(typeinfo_t *value,typeinfo_t *dest);
-typecheck_result typeinfo_is_assignable_to_class(typeinfo_t *value,classref_or_classinfo dest);
-
-/* initialization functions *************************************************/
-
-/* RETURN VALUE (bool):
- *     true.............ok,
- *     false............an exception has been thrown.
- *
- * RETURN VALUE (int):
- *     >= 0.............ok,
- *     -1...............an exception has been thrown.
- */
-void typeinfo_init_classinfo(typeinfo_t *info,classinfo *c);
-bool typeinfo_init_class(typeinfo_t *info,classref_or_classinfo c);
-bool typeinfo_init_component(typeinfo_t *srcarray,typeinfo_t *dst);
-
-bool typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo_t *info);
-bool typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,
-                                   typeinfo_t *infobuf,
-                                   int buflen,bool twoword,
-                                   u1 *returntype,typeinfo_t *returntypeinfo);
-bool  typedescriptor_init_from_typedesc(typedescriptor_t *td,
-                                                                           typedesc *desc);
-bool  typeinfo_init_varinfo_from_typedesc(varinfo *var,
-                                                                           typedesc *desc);
-int  typedescriptors_init_from_methoddesc(typedescriptor_t *td,
-                                                                                 methoddesc *desc,
-                                                                                 int buflen,bool twoword,int startindex,
-                                                                                 typedescriptor_t *returntype);
-bool typeinfo_init_varinfos_from_methoddesc(varinfo *vars,
-                                                                                 methoddesc *desc,
-                                                                                 int buflen, int startindex,
-                                                                                 s4 *map,
-                                                                                 typedescriptor_t *returntype);
-
-void typeinfo_clone(typeinfo_t *src,typeinfo_t *dest);
-
-/* freeing memory ***********************************************************/
-
-void typeinfo_free(typeinfo_t *info);
-
-/* functions for merging types **********************************************/
-
-typecheck_result typeinfo_merge(methodinfo *m,typeinfo_t *dest,typeinfo_t* y);
-
-/* debugging helpers ********************************************************/
-
-#ifdef TYPEINFO_DEBUG
-
-#include <stdio.h>
-
-void typeinfo_test();
-void typeinfo_print_class(FILE *file,classref_or_classinfo c);
-void typeinfo_print(FILE *file,typeinfo_t *info,int indent);
-void typeinfo_print_short(FILE *file,typeinfo_t *info);
-void typeinfo_print_type(FILE *file,int type,typeinfo_t *info);
-void typedescriptor_print(FILE *file,typedescriptor_t *td);
-void typevector_print(FILE *file,varinfo *vec,int size);
-
-#endif /* TYPEINFO_DEBUG */
-
-#ifdef __cplusplus
-} 
-#endif
-
-#endif /* _TYPEINFO_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/jit/verify/typeinfo.hpp b/src/vm/jit/verify/typeinfo.hpp
new file mode 100644 (file)
index 0000000..ea42925
--- /dev/null
@@ -0,0 +1,538 @@
+/* src/vm/jit/verify/typeinfo.h - type system used by the type checker
+
+   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 _TYPEINFO_H
+#define _TYPEINFO_H
+
+/* resolve typedef cycles *****************************************************/
+
+typedef struct typeinfo            typeinfo_t;
+typedef struct typeinfo_mergedlist typeinfo_mergedlist_t;
+typedef struct typedescriptor      typedescriptor_t;
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "vm/global.h"
+#include "vm/references.h"
+
+
+/* configuration **************************************************************/
+
+/*
+ * TYPECHECK_STATISTICS activates gathering statistical information.
+ * TYPEINFO_DEBUG activates debug checks and debug helpers in typeinfo.c
+ * TYPECHECK_DEBUG activates debug checks in typecheck.c
+ * TYPEINFO_DEBUG_TEST activates the typeinfo test at startup.
+ * TYPECHECK_VERBOSE_IMPORTANT activates important debug messages
+ * TYPECHECK_VERBOSE activates all debug messages
+ * TYPEINFO_VERBOSE activates debug prints in typeinfo.c
+ */
+#ifdef ENABLE_VERIFIER
+#ifndef NDEBUG
+/*#define TYPECHECK_STATISTICS*/
+#define TYPEINFO_DEBUG
+/*#define TYPEINFO_VERBOSE*/
+#define TYPECHECK_DEBUG
+/*#define TYPEINFO_DEBUG_TEST*/
+/*#define TYPECHECK_VERBOSE*/
+/*#define TYPECHECK_VERBOSE_IMPORTANT*/
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+#define TYPECHECK_VERBOSE_OPT
+#endif
+#endif
+#endif
+
+#ifdef TYPECHECK_VERBOSE_OPT
+extern bool opt_typecheckverbose;
+#endif
+
+/* types **********************************************************************/
+
+/* typecheck_result - return type for boolean and tristate  functions     */
+/*                    which may also throw exceptions (typecheck_FAIL).   */
+
+/* NOTE: Use the enum values, not the uppercase #define macros!          */
+#define TYPECHECK_MAYBE  0x02
+#define TYPECHECK_FAIL   0x04
+
+typedef enum {
+       typecheck_FALSE = false,
+       typecheck_TRUE  = true,
+       typecheck_MAYBE = TYPECHECK_MAYBE,
+       typecheck_FAIL  = TYPECHECK_FAIL
+} typecheck_result;
+
+/* check that typecheck_MAYBE is not ambiguous */
+#if TYPECHECK_MAYBE == true
+#error "`typecheck_MAYBE` must not be the same as `true`"
+#endif
+#if TYPECHECK_MAYBE == false
+#error "`typecheck_MAYBE` must not be the same as `false`"
+#endif
+
+/* check that typecheck_FAIL is not ambiguous */
+#if (true & TYPECHECK_FAIL) != 0
+#error "`true` must not have bit 0x02 set (conflicts with typecheck_FAIL)"
+#endif
+
+/* data structures for the type system ****************************************/
+
+/* The typeinfo structure stores detailed information on address types.
+ * (stack elements, variables, etc. with type == TYPE_ADR.)
+ *
+ * There are two kinds of address types which can be distinguished by
+ * the value of the typeclass field:
+ *
+ * 1) typeclass == NULL: returnAddress type
+ *                       use TYPEINFO_IS_PRIMITIVE to test for this
+ *
+ * 2) typeclass != NULL: reference type
+ *                       use TYPEINFO_IS_REFERENCE to test for this
+ *
+ * Note: For non-address types either there is no typeinfo allocated
+ * or the fields of the typeinfo struct contain undefined values!
+ * DO NOT access the typeinfo for non-address types!
+ *
+ * CAUTION: The typeinfo structure should be considered opaque outside of
+ *          typeinfo.[ch]. Please use the macros and functions defined here to
+ *          access typeinfo structures!
+ */
+
+/* At all times *exactly one* of the following conditions is true for
+ * a particular typeinfo struct:
+ *
+ * A) typeclass == NULL
+ *
+ *        This is a returnAddress type.
+ *
+ *        Use TYPEINFO_IS_PRIMITIVE to check for this.
+ *        Use TYPEINFO_RETURNADDRESS to access the pointer in elementclass.
+ *        Don't access other fields of the struct.
+ *
+ * B) typeclass == pseudo_class_Null
+ *
+ *        This is the null-reference type. 
+ *        Use TYPEINFO_IS_NULLTYPE to check for this.
+ *        Don't access other fields of the struct.
+ *
+ * C) typeclass == pseudo_class_New
+ *
+ *        This is an 'uninitialized object' type. elementclass can be
+ *        cast to instruction* and points to the NEW instruction
+ *        responsible for creating this type.
+ *
+ *        Use TYPEINFO_NEWOBJECT_INSTRUCTION to access the pointer in
+ *        elementclass.
+ *        Don't access other fields of the struct.
+ *
+ * D) typeclass == pseudo_class_Arraystub
+ *
+ *        This type is used to represent the result of merging array types
+ *        with incompatible component types. An arraystub allows no access
+ *        to its components (since their type is undefined), but it allows
+ *        operations which act directly on an arbitrary array type (such as
+ *        requesting the array size).
+ *
+ *        NOTE: An array stub does *not* count as an array. It has dimension
+ *              zero.
+ *
+ *        Otherwise like a normal class reference type.
+ *        Don't access other fields of the struct.
+ *
+ * E) typeclass is an array class
+ *
+ *        An array reference.
+ *            elementclass...typeclass of the element type
+ *            dimension......dimension of the array (>=1)
+ *            elementtype....element type (ARRAYTYPE_...)
+ *            merged.........mergedlist of the element type
+ *
+ *        Use TYPEINFO_IS_ARRAY to check for this case.
+ *
+ *        The elementclass may be one of the following:
+ *        1) pseudo_class_Arraystub
+ *        2) an unresolved type
+ *        3) a loaded interface
+ *        4) a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
+ *                Note: `merged` may be used
+ *        5) (BOOTSTRAP)java.lang.Object
+ *                Note: `merged` may be used
+ *
+ *        For the semantics of the merged field in cases 4) and 5) consult the 
+ *        corresponding descriptions with `elementclass` replaced by `typeclass`.
+ *
+ * F) typeclass is an unresolved type (a symbolic class/interface reference)
+ *
+ *        The type has not been resolved yet. (Meaning it corresponds to an
+ *        unloaded class or interface).
+ *        Don't access other fields of the struct.
+ *
+ * G) typeclass is a loaded interface
+ *
+ *        An interface reference type.
+ *        Don't access other fields of the struct.
+ *
+ * H) typeclass is a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
+ *
+ *        A loaded class type.
+ *        All classref_or_classinfos in u.merged.list (if any) are
+ *        loaded subclasses of typeclass (no interfaces, array classes, or
+ *        unresolved types).
+ *        Don't access other fields of the struct.
+ *
+ * I) typeclass is (BOOTSTRAP)java.lang.Object
+ *
+ *        The most general kind of reference type.
+ *        In this case u.merged.count and u.merged.list
+ *        are valid and may be non-zero.
+ *        The classref_or_classinfos in u.merged.list (if any) may be
+ *        classes, interfaces, pseudo classes or unresolved types.
+ *        Don't access other fields of the struct.
+ */
+
+/* The following algorithm is used to determine if the type described
+ * by this typeinfo struct supports the interface X:  * XXX add MAYBE *
+ *
+ *     1) If typeclass is X or a subinterface of X the answer is "yes".
+ *     2) If typeclass is a (pseudo) class implementing X the answer is "yes".
+ *     3) If typeclass is not an array and u.merged.count>0
+ *        and all classes/interfaces in u.merged.list implement X
+ *        the answer is "yes".
+ *     4) If none of the above is true the answer is "no".
+ */
+
+/*
+ * CAUTION: The typeinfo structure should be considered opaque outside of
+ *          typeinfo.[ch]. Please use the macros and functions defined here to
+ *          access typeinfo structures!
+ */
+struct typeinfo {
+       classref_or_classinfo  typeclass;
+       classref_or_classinfo  elementclass; /* valid if dimension>0 */ /* various uses! */
+       typeinfo_mergedlist_t *merged;
+       u1                     dimension;
+       u1                     elementtype;  /* valid if dimension>0           */
+};
+
+struct typeinfo_mergedlist {
+       s4                    count;
+       classref_or_classinfo list[1];       /* variable length!                        */
+};
+
+/* a type descriptor stores a basic type and the typeinfo                */
+/* this is used for storing the type of a local variable, and for        */
+/* storing types in the signature of a method                            */
+
+struct typedescriptor {
+       typeinfo_t      typeinfo; /* valid if type == TYPE_ADR               */
+       u1              type;     /* basic type (TYPE_INT, ...)              */
+};
+
+/****************************************************************************/
+/* MACROS                                                                   */
+/****************************************************************************/
+
+/* NOTE: The TYPEINFO macros take typeinfo *structs*, not pointers as
+ *       arguments.  You have to dereference any pointers.
+ */
+
+/* typevectors **************************************************************/
+
+#define TYPEVECTOR_SIZE(size)                                          \
+    ((size) * sizeof(varinfo)) 
+
+#define DNEW_TYPEVECTOR(size)                                          \
+    ((varinfo *) DumpMemory::allocate(TYPEVECTOR_SIZE(size)))
+
+#define DMNEW_TYPEVECTOR(num,size)                                     \
+    ((varinfo *) DumpMemory::allocate((num) * TYPEVECTOR_SIZE(size)))
+
+#define MGET_TYPEVECTOR(array,index,size) \
+    ((varinfo*) (((u1*)(array)) + TYPEVECTOR_SIZE(size) * (index)))
+
+/* internally used macros ***************************************************/
+
+/* internal, don't use this explicitly! */
+#define TYPEINFO_ALLOCMERGED(mergedlist,count)                                 \
+    do {(mergedlist) = (typeinfo_mergedlist_t *) DumpMemory::allocate(sizeof(typeinfo_mergedlist_t) \
+            + ((count)-1)*sizeof(classinfo*));} while(0)
+
+/* internal, don't use this explicitly! */
+#define TYPEINFO_FREEMERGED(mergedlist)
+
+/* internal, don't use this explicitly! */
+#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
+
+/* macros for type queries **************************************************/
+
+#define TYPEINFO_IS_PRIMITIVE(info)                             \
+            ((info).typeclass.any == NULL)
+
+#define TYPEINFO_IS_REFERENCE(info)                             \
+            ((info).typeclass.any != NULL)
+
+#define TYPEINFO_IS_NULLTYPE(info)                              \
+            ((info).typeclass.cls == pseudo_class_Null)
+
+#define TYPEINFO_IS_NEWOBJECT(info)                             \
+            ((info).typeclass.cls == pseudo_class_New)
+
+#define TYPEINFO_IS_JAVA_LANG_CLASS(info)                       \
+            ((info).typeclass.cls == class_java_lang_Class)
+
+/* only use this if TYPEINFO_IS_PRIMITIVE returned true! */
+#define TYPEINFO_RETURNADDRESS(info)                            \
+            ((info).elementclass.any)
+
+/* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
+#define TYPEINFO_NEWOBJECT_INSTRUCTION(info)                    \
+               ((info).elementclass.any)
+
+/* only use this if TYPEINFO_IS_JAVA_LANG_CLASS returned true! */
+#define TYPEINFO_JAVA_LANG_CLASS_CLASSREF(info)                 \
+               ((info).elementclass.ref)
+
+/* macros for array type queries ********************************************/
+
+#define TYPEINFO_IS_ARRAY(info)                                 \
+            ( TYPEINFO_IS_REFERENCE(info)                       \
+              && ((info).dimension != 0) )
+
+#define TYPEINFO_IS_SIMPLE_ARRAY(info)                          \
+            ( ((info).dimension == 1) )
+
+#define TYPEINFO_IS_ARRAY_ARRAY(info)                           \
+            ( ((info).dimension >= 2) )
+
+#define TYPEINFO_IS_PRIMITIVE_ARRAY(info,arraytype)             \
+            ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
+              && ((info).elementtype == (arraytype)) )
+
+#define TYPEINFO_IS_OBJECT_ARRAY(info)                          \
+            ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
+              && ((info).elementclass.any != NULL) )
+
+/* assumes that info describes an array type */
+#define TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info)                 \
+            ( ((info).elementclass.any != NULL)                 \
+              || ((info).dimension >= 2) )
+
+#define TYPEINFO_IS_ARRAY_OF_REFS(info)                         \
+            ( TYPEINFO_IS_ARRAY(info)                           \
+              && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
+
+#define TYPE_IS_RETURNADDRESS(type,info)                        \
+            ( ((type)==TYPE_RET)                                \
+              && TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPE_IS_REFERENCE(type,info)                            \
+            ( ((type)==TYPE_ADR)                                \
+              && !TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPEDESC_IS_RETURNADDRESS(td)                           \
+            TYPE_IS_RETURNADDRESS((td).type,(td).typeinfo)
+
+#define TYPEDESC_IS_REFERENCE(td)                               \
+            TYPE_IS_REFERENCE((td).type,(td).typeinfo)
+
+/* queries allowing the null type ********************************************/
+
+#define TYPEINFO_MAYBE_ARRAY(info)                              \
+    (TYPEINFO_IS_ARRAY(info) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_PRIMITIVE_ARRAY(info,at)                 \
+    (TYPEINFO_IS_PRIMITIVE_ARRAY(info,at) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_ARRAY_OF_REFS(info)                      \
+    (TYPEINFO_IS_ARRAY_OF_REFS(info) || TYPEINFO_IS_NULLTYPE(info))
+
+/* macros for initializing typeinfo structures ******************************/
+
+#define TYPEINFO_INIT_PRIMITIVE(info)                           \
+         do {(info).typeclass.any = NULL;                       \
+             (info).elementclass.any = NULL;                    \
+             (info).merged = NULL;                              \
+             (info).dimension = 0;                              \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_RETURNADDRESS(info,adr)                   \
+         do {(info).typeclass.any = NULL;                       \
+             (info).elementclass.any = (adr);                   \
+             (info).merged = NULL;                              \
+             (info).dimension = 0;                              \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo)   \
+         do {(info).typeclass.cls = (cinfo);            \
+             (info).elementclass.any = NULL;            \
+             (info).merged = NULL;                      \
+             (info).dimension = 0;                      \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_JAVA_LANG_CLASS(info,c)                   \
+         do {(info).typeclass.any = class_java_lang_Class;      \
+             (info).elementclass = (c);                         \
+             (info).merged = NULL;                              \
+             (info).dimension = 0;                              \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_NULLTYPE(info)                            \
+            TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,pseudo_class_Null)
+
+#define TYPEINFO_INIT_NEWOBJECT(info,instr)             \
+         do {(info).typeclass.cls = pseudo_class_New;   \
+             (info).elementclass.any = (instr);         \
+             (info).merged = NULL;                      \
+             (info).dimension = 0;                      \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_PRIMITIVE_ARRAY(info,arraytype)                   \
+    typeinfo_init_classinfo(&(info),primitivetype_table[arraytype].arrayclass);
+
+/* macros for copying types (destinition is not checked or freed) ***********/
+
+/* TYPEINFO_COPY makes a shallow copy, the merged pointer is simply copied. */
+#define TYPEINFO_COPY(src,dst)                                  \
+    do {(dst) = (src);} while(0)
+
+/* TYPEINFO_CLONE makes a deep copy, the merged list (if any) is duplicated
+ * into a newly allocated array.
+ */
+#define TYPEINFO_CLONE(src,dst)                                 \
+    do {(dst) = (src);                                          \
+        if ((dst).merged) typeinfo_clone(&(src),&(dst));} while(0)
+
+/****************************************************************************/
+/* FUNCTIONS                                                                */
+/****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" { 
+#endif
+
+/* typevector functions *****************************************************/
+
+/* element read-only access */
+bool typevector_checktype(varinfo *set,int index,int type);
+bool typevector_checkreference(varinfo *set,int index);
+bool typevector_checkretaddr(varinfo *set,int index);
+
+/* element write access */
+void typevector_store(varinfo *set,int index,int type,typeinfo_t *info);
+void typevector_store_retaddr(varinfo *set,int index,typeinfo_t *info);
+bool typevector_init_object(varinfo *set,void *ins,classref_or_classinfo initclass,int size);
+
+/* vector functions */
+varinfo *typevector_copy(varinfo *src,int size);
+void typevector_copy_inplace(varinfo *src,varinfo *dst,int size);
+typecheck_result typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size);
+
+/* inquiry functions (read-only) ********************************************/
+
+bool typeinfo_is_array(typeinfo_t *info);
+bool typeinfo_is_primitive_array(typeinfo_t *info,int arraytype);
+bool typeinfo_is_array_of_refs(typeinfo_t *info);
+
+typecheck_result typeinfo_is_assignable(typeinfo_t *value,typeinfo_t *dest);
+typecheck_result typeinfo_is_assignable_to_class(typeinfo_t *value,classref_or_classinfo dest);
+
+/* initialization functions *************************************************/
+
+/* RETURN VALUE (bool):
+ *     true.............ok,
+ *     false............an exception has been thrown.
+ *
+ * RETURN VALUE (int):
+ *     >= 0.............ok,
+ *     -1...............an exception has been thrown.
+ */
+void typeinfo_init_classinfo(typeinfo_t *info,classinfo *c);
+bool typeinfo_init_class(typeinfo_t *info,classref_or_classinfo c);
+bool typeinfo_init_component(typeinfo_t *srcarray,typeinfo_t *dst);
+
+bool typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo_t *info);
+bool typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,
+                                   typeinfo_t *infobuf,
+                                   int buflen,bool twoword,
+                                   u1 *returntype,typeinfo_t *returntypeinfo);
+bool  typedescriptor_init_from_typedesc(typedescriptor_t *td,
+                                                                           typedesc *desc);
+bool  typeinfo_init_varinfo_from_typedesc(varinfo *var,
+                                                                           typedesc *desc);
+int  typedescriptors_init_from_methoddesc(typedescriptor_t *td,
+                                                                                 methoddesc *desc,
+                                                                                 int buflen,bool twoword,int startindex,
+                                                                                 typedescriptor_t *returntype);
+bool typeinfo_init_varinfos_from_methoddesc(varinfo *vars,
+                                                                                 methoddesc *desc,
+                                                                                 int buflen, int startindex,
+                                                                                 s4 *map,
+                                                                                 typedescriptor_t *returntype);
+
+void typeinfo_clone(typeinfo_t *src,typeinfo_t *dest);
+
+/* freeing memory ***********************************************************/
+
+void typeinfo_free(typeinfo_t *info);
+
+/* functions for merging types **********************************************/
+
+typecheck_result typeinfo_merge(methodinfo *m,typeinfo_t *dest,typeinfo_t* y);
+
+/* debugging helpers ********************************************************/
+
+#ifdef TYPEINFO_DEBUG
+
+#include <stdio.h>
+
+void typeinfo_test();
+void typeinfo_print_class(FILE *file,classref_or_classinfo c);
+void typeinfo_print(FILE *file,typeinfo_t *info,int indent);
+void typeinfo_print_short(FILE *file,typeinfo_t *info);
+void typeinfo_print_type(FILE *file,int type,typeinfo_t *info);
+void typedescriptor_print(FILE *file,typedescriptor_t *td);
+void typevector_print(FILE *file,varinfo *vec,int size);
+
+#endif /* TYPEINFO_DEBUG */
+
+#ifdef __cplusplus
+} 
+#endif
+
+#endif /* _TYPEINFO_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:
+ */
index c2cbea33fb035eb017d512e0ec0540e6992cc246..18e86af090d752928ae9b0e0fbf5c9f3b3a4eb3c 100644 (file)
@@ -63,7 +63,7 @@
 #include "vm/jit/jit.hpp"
 #include "vm/jit/linenumbertable.hpp"
 #include "vm/jit/methodheader.h"
-#include "vm/jit/parse.h"
+#include "vm/jit/parse.hpp"
 #include "vm/jit/patcher-common.hpp"
 #include "vm/jit/reg.h"
 #include "vm/jit/replace.hpp"
index fd248a596b4743b2fee491ed2acc697a56b58653..10dd05b45d7455b3178fa02b916ecad2da4e6d6f 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "vm/jit/x86_64/md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/global.h"
 
 #include "vm/jit/abi.h"
diff --git a/src/vm/linker.c b/src/vm/linker.c
deleted file mode 100644 (file)
index e5883f0..0000000
+++ /dev/null
@@ -1,1320 +0,0 @@
-/* src/vm/linker.c - class linker 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 "vm/types.h"
-
-#include "mm/memory.h"
-
-#include "native/native.hpp"
-
-#include "threads/lock.hpp"
-#include "threads/mutex.hpp"
-
-#include "toolbox/logging.h"
-
-#include "vm/access.h"
-#include "vm/array.hpp"
-#include "vm/class.hpp"
-#include "vm/classcache.h"
-#include "vm/exceptions.hpp"
-#include "vm/globals.hpp"
-#include "vm/loader.hpp"
-#include "vm/options.h"
-#include "vm/primitive.hpp"
-#include "vm/rt-timing.h"
-#include "vm/string.hpp"
-#include "vm/vm.hpp"
-
-#include "vm/jit/asmpart.h"
-#include "vm/jit/stubs.hpp"
-
-
-/* debugging macros ***********************************************************/
-
-#if !defined(NDEBUG)
-# define TRACELINKCLASS(c) \
-    do { \
-        if (opt_TraceLinkClass) { \
-            log_start(); \
-            log_print("[Linking "); \
-            class_print((c)); \
-            log_print("]"); \
-            log_finish(); \
-        } \
-    } while (0)
-#else
-# define TRACELINKCLASS(c)
-#endif
-
-
-/* #include "vm/resolve.hpp" */
-/* copied prototype to avoid bootstrapping problem: */
-classinfo *resolve_classref_or_classinfo_eager(classref_or_classinfo cls, bool checkaccess);
-
-#if defined(ENABLE_STATISTICS)
-# include "vm/statistics.h"
-#endif
-
-#if !defined(NDEBUG) && defined(ENABLE_INLINING)
-#define INLINELOG(code)  do { if (opt_TraceInlining) { code } } while (0)
-#else
-#define INLINELOG(code)
-#endif
-
-
-/* global variables ***********************************************************/
-
-static s4 interfaceindex;       /* sequential numbering of interfaces         */
-static s4 classvalue;
-
-Mutex *linker_classrenumber_mutex;
-
-
-/* private functions **********************************************************/
-
-static classinfo *link_class_intern(classinfo *c);
-static arraydescriptor *link_array(classinfo *c);
-static void linker_compute_class_values(classinfo *c);
-static void linker_compute_subclasses(classinfo *c);
-static bool linker_addinterface(classinfo *c, classinfo *ic);
-static s4 class_highestinterface(classinfo *c);
-
-
-/* linker_init *****************************************************************
-
-   Initializes the linker subsystem and links classes required for the
-   primitive table.
-
-*******************************************************************************/
-
-void linker_preinit(void)
-{
-       TRACESUBSYSTEMINITIALIZATION("linker_preinit");
-
-       /* Reset interface index. */
-
-       interfaceindex = 0;
-
-#if defined(ENABLE_THREADS)
-       /* create the global mutex */
-
-       linker_classrenumber_mutex = Mutex_new();
-#endif
-
-       /* Link the most basic classes. */
-
-       if (!link_class(class_java_lang_Object))
-               vm_abort("linker_preinit: linking java/lang/Object failed");
-
-#if defined(ENABLE_JAVASE)
-       if (!link_class(class_java_lang_Cloneable))
-               vm_abort("linker_preinit: linking java/lang/Cloneable failed");
-
-       if (!link_class(class_java_io_Serializable))
-               vm_abort("linker_preinit: linking java/io/Serializable failed");
-#endif
-}
-
-
-/* linker_init *****************************************************************
-
-   Links all classes required in the VM.
-
-*******************************************************************************/
-
-void linker_init(void)
-{
-       TRACESUBSYSTEMINITIALIZATION("linker_init");
-
-       /* Link java.lang.Class as first class of the system, because we
-       need it's vftbl for all other classes so we can use a class as
-       object. */
-
-       if (!link_class(class_java_lang_Class))
-               vm_abort("linker_init: linking java/lang/Class failed");
-
-       /* Now set the header.vftbl of all classes which were created
-       before java.lang.Class was linked. */
-
-       class_postset_header_vftbl();
-
-       /* Link primitive-type wrapping classes. */
-
-#if defined(ENABLE_JAVASE)
-       if (!link_class(class_java_lang_Void))
-               vm_abort("linker_init: linking failed");
-#endif
-
-       if (!link_class(class_java_lang_Boolean))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_Byte))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_Character))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_Short))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_Integer))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_Long))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_Float))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_Double))
-               vm_abort("linker_init: linking failed");
-
-       /* Link important system classes. */
-
-       if (!link_class(class_java_lang_String))
-               vm_abort("linker_init: linking java/lang/String failed");
-
-#if defined(ENABLE_JAVASE)
-       if (!link_class(class_java_lang_ClassLoader))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_SecurityManager))
-               vm_abort("linker_init: linking failed");
-#endif
-
-       if (!link_class(class_java_lang_System))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_Thread))
-               vm_abort("linker_init: linking failed");
-
-#if defined(ENABLE_JAVASE)
-       if (!link_class(class_java_lang_ThreadGroup))
-               vm_abort("linker_init: linking failed");
-#endif
-
-       if (!link_class(class_java_lang_Throwable))
-               vm_abort("linker_init: linking failed");
-
-#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-       if (!link_class(class_java_lang_VMSystem))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_VMThread))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_VMThrowable))
-               vm_abort("linker_init: linking failed");
-#endif
-
-       /* Important system exceptions. */
-
-       if (!link_class(class_java_lang_Exception))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_ClassNotFoundException))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_RuntimeException))
-               vm_abort("linker_init: linking failed");
-
-       /* some classes which may be used more often */
-
-#if defined(ENABLE_JAVASE)
-       if (!link_class(class_java_lang_StackTraceElement))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_reflect_Constructor))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_reflect_Field))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_reflect_Method))
-               vm_abort("linker_init: linking failed");
-
-# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
-       if (!link_class(class_java_lang_reflect_VMConstructor))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_reflect_VMField))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_lang_reflect_VMMethod))
-               vm_abort("linker_init: linking failed");
-# endif
-
-       if (!link_class(class_java_security_PrivilegedAction))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_util_Vector))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_java_util_HashMap))
-               vm_abort("linker_init: linking failed");
-
-# if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
-       if (!link_class(class_sun_misc_Signal))
-               vm_abort("linker_init: linking failed");
-
-       if (!link_class(class_sun_reflect_MagicAccessorImpl))
-               vm_abort("linker_init: linking failed");
-# endif
-
-       if (!link_class(arrayclass_java_lang_Object))
-               vm_abort("linker_init: linking failed");
-#endif
-
-
-       /* create pseudo classes used by the typechecker */
-
-    /* pseudo class for Arraystubs (extends java.lang.Object) */
-
-       pseudo_class_Arraystub                   =
-               class_create_classinfo(utf_new_char("$ARRAYSTUB$"));
-       pseudo_class_Arraystub->state           |= CLASS_LOADED;
-       pseudo_class_Arraystub->super            = class_java_lang_Object;
-
-#if defined(ENABLE_JAVASE)
-
-       pseudo_class_Arraystub->interfacescount  = 2;
-       pseudo_class_Arraystub->interfaces       = MNEW(classinfo*, 2);
-       pseudo_class_Arraystub->interfaces[0]    = class_java_lang_Cloneable;
-       pseudo_class_Arraystub->interfaces[1]    = class_java_io_Serializable;
-
-#elif defined(ENABLE_JAVAME_CLDC1_1)
-
-       pseudo_class_Arraystub->interfacescount    = 0;
-       pseudo_class_Arraystub->interfaces         = NULL;
-
-#else
-# error unknown Java configuration
-#endif
-
-       if (!classcache_store_unique(pseudo_class_Arraystub))
-               vm_abort("linker_init: could not cache pseudo_class_Arraystub");
-
-       if (!link_class(pseudo_class_Arraystub))
-               vm_abort("linker_init: linking pseudo_class_Arraystub failed");
-
-       /* pseudo class representing the null type */
-
-       pseudo_class_Null         = class_create_classinfo(utf_new_char("$NULL$"));
-       pseudo_class_Null->state |= CLASS_LOADED;
-       pseudo_class_Null->super  = class_java_lang_Object;
-
-       if (!classcache_store_unique(pseudo_class_Null))
-               vm_abort("linker_init: could not cache pseudo_class_Null");
-
-       if (!link_class(pseudo_class_Null))
-               vm_abort("linker_init: linking failed");
-
-       /* pseudo class representing new uninitialized objects */
-    
-       pseudo_class_New         = class_create_classinfo(utf_new_char("$NEW$"));
-       pseudo_class_New->state |= CLASS_LOADED;
-       pseudo_class_New->state |= CLASS_LINKED; /* XXX is this allright? */
-       pseudo_class_New->super  = class_java_lang_Object;
-
-       if (!classcache_store_unique(pseudo_class_New))
-               vm_abort("linker_init: could not cache pseudo_class_New");
-
-       /* Correct vftbl-entries (retarded loading and linking of class
-          java/lang/String). */
-
-       stringtable_update();
-}
-
-
-/* link_class ******************************************************************
-
-   Wrapper function for link_class_intern to ease monitor enter/exit
-   and exception handling.
-
-*******************************************************************************/
-
-classinfo *link_class(classinfo *c)
-{
-       classinfo *r;
-#if defined(ENABLE_RT_TIMING)
-       struct timespec time_start, time_end;
-#endif
-
-       RT_TIMING_GET_TIME(time_start);
-
-       if (c == NULL) {
-               exceptions_throw_nullpointerexception();
-               return NULL;
-       }
-
-       LOCK_MONITOR_ENTER(c);
-
-       /* Maybe the class is currently linking or is already linked.*/
-
-       if ((c->state & CLASS_LINKING) || (c->state & CLASS_LINKED)) {
-               LOCK_MONITOR_EXIT(c);
-
-               return c;
-       }
-
-#if defined(ENABLE_STATISTICS)
-       /* measure time */
-
-       if (opt_getcompilingtime)
-               compilingtime_stop();
-
-       if (opt_getloadingtime)
-               loadingtime_start();
-#endif
-
-       /* call the internal function */
-
-       r = link_class_intern(c);
-
-       /* If return value is NULL, we had a problem and the class is not
-          linked. */
-
-       if (r == NULL)
-               c->state &= ~CLASS_LINKING;
-
-#if defined(ENABLE_STATISTICS)
-       /* measure time */
-
-       if (opt_getloadingtime)
-               loadingtime_stop();
-
-       if (opt_getcompilingtime)
-               compilingtime_start();
-#endif
-
-       LOCK_MONITOR_EXIT(c);
-
-       RT_TIMING_GET_TIME(time_end);
-
-       RT_TIMING_TIME_DIFF(time_start,time_end,RT_TIMING_LINK_TOTAL);
-
-       return r;
-}
-
-
-/* linker_overwrite_method *****************************************************
-
-   Overwrite a method with another one, update method flags and check
-   assumptions.
-
-   IN:
-      mg................the general method being overwritten
-         ms................the overwriting (more specialized) method
-         wl................worklist where to add invalidated methods
-
-   RETURN VALUE:
-      true..............everything ok
-         false.............an exception has been thrown
-
-*******************************************************************************/
-
-static bool linker_overwrite_method(methodinfo *mg,
-                                                                       methodinfo *ms,
-                                                                       method_worklist **wl)
-{
-       classinfo *cg;
-       classinfo *cs;
-
-       cg = mg->clazz;
-       cs = ms->clazz;
-
-       /* overriding a final method is illegal */
-
-       if (mg->flags & ACC_FINAL) {
-               exceptions_throw_verifyerror(mg, "Overriding final method");
-               return false;
-       }
-
-       /* method ms overwrites method mg */
-
-#if defined(ENABLE_VERIFIER)
-       /* Add loading constraints (for the more general types of method mg). */
-       /* Not for <init>, as it is not invoked virtually.                    */
-
-       if ((ms->name != utf_init)
-                       && !classcache_add_constraints_for_params(
-                               cs->classloader, cg->classloader, mg))
-       {
-               return false;
-       }
-#endif
-
-       /* inherit the vftbl index, and record the overwriting */
-
-       ms->vftblindex = mg->vftblindex;
-       ms->overwrites = mg;
-
-       /* update flags and check assumptions */
-       /* <init> methods are a special case, as they are never dispatched dynamically */
-
-       if ((ms->flags & ACC_METHOD_IMPLEMENTED) && ms->name != utf_init) {
-               do {
-
-#if defined(ENABLE_TLH)
-                       if (mg->flags & ACC_METHOD_MONOMORPHY_USED) {
-                               printf("%s/%s is evil! the siner is %s/%s\n", mg->clazz->name->text, mg->name->text,
-                                       ms->clazz->name->text, ms->name->text);
-                               ms->flags |= ACC_METHOD_PARENT_MONOMORPHY_USED;                                 
-                       }
-#endif
-
-                       if (mg->flags & ACC_METHOD_IMPLEMENTED) {
-                               /* this adds another implementation */
-
-                               mg->flags &= ~ACC_METHOD_MONOMORPHIC;
-
-                               INLINELOG( printf("becomes polymorphic: "); method_println(mg); );
-
-                               method_break_assumption_monomorphic(mg, wl);
-                       }
-                       else {
-                               /* this is the first implementation */
-
-                               mg->flags |= ACC_METHOD_IMPLEMENTED;
-
-                               INLINELOG( printf("becomes implemented: "); method_println(mg); );
-                       }
-
-                       ms = mg;
-                       mg = mg->overwrites;
-               } while (mg != NULL);
-       }
-
-       return true;
-}
-
-
-/* link_class_intern ***********************************************************
-
-   Tries to link a class. The function calculates the length in bytes
-   that an instance of this class requires as well as the VTBL for
-   methods and interface methods.
-       
-*******************************************************************************/
-
-static classinfo *link_class_intern(classinfo *c)
-{
-       classinfo *super;             /* super class                              */
-       classinfo *tc;                /* temporary class variable                 */
-       s4 supervftbllength;          /* vftbllegnth of super class               */
-       s4 vftbllength;               /* vftbllength of current class             */
-       s4 interfacetablelength;      /* interface table length                   */
-       vftbl_t *v;                   /* vftbl of current class                   */
-       s4 i;                         /* interface/method/field counter           */
-       arraydescriptor *arraydesc;   /* descriptor for array classes             */
-       method_worklist *worklist;    /* worklist for recompilation               */
-#if defined(ENABLE_RT_TIMING)
-       struct timespec time_start, time_resolving, time_compute_vftbl,
-                                       time_abstract, time_compute_iftbl, time_fill_vftbl,
-                                       time_offsets, time_fill_iftbl, time_finalizer,
-                                       time_subclasses;
-#endif
-
-       RT_TIMING_GET_TIME(time_start);
-
-       TRACELINKCLASS(c);
-
-       /* the class must be loaded */
-
-       /* XXX should this be a specific exception? */
-       assert(c->state & CLASS_LOADED);
-
-       /* This is check in link_class. */
-
-       assert(!(c->state & CLASS_LINKED));
-
-       /* cache the self-reference of this class                          */
-       /* we do this for cases where the defining loader of the class     */
-       /* has not yet been recorded as an initiating loader for the class */
-       /* this is needed so subsequent code can assume that self-refs     */
-       /* will always resolve lazily                                      */
-       /* No need to do it for the bootloader - it is always registered   */
-       /* as initiating loader for the classes it loads.                  */
-       if (c->classloader)
-               classcache_store(c->classloader,c,false);
-
-       /* this class is currently linking */
-
-       c->state |= CLASS_LINKING;
-
-       arraydesc = NULL;
-       worklist = NULL;
-
-       /* Link the super interfaces. */
-
-       for (i = 0; i < c->interfacescount; i++) {
-               tc = c->interfaces[i];
-
-               if (!(tc->state & CLASS_LINKED))
-                       if (!link_class(tc))
-                               return NULL;
-       }
-       
-       /* check super class */
-
-       super = NULL;
-
-       /* Check for java/lang/Object. */
-
-       if (c->super == NULL) {
-               c->index = 0;
-               c->instancesize = sizeof(java_object_t);
-               
-               vftbllength = supervftbllength = 0;
-
-               c->finalizer = NULL;
-       }
-       else {
-               /* Get super class. */
-
-               super = c->super;
-
-               /* Link the super class if necessary. */
-               
-               if (!(super->state & CLASS_LINKED))
-                       if (!link_class(super))
-                               return NULL;
-
-               /* OR the ACC_CLASS_HAS_POINTERS and the ACC_CLASS_REFERENCE_*
-                  flags. */
-
-               c->flags |= (super->flags &
-                                        (ACC_CLASS_HAS_POINTERS | ACC_CLASS_REFERENCE_MASK));
-
-               /* handle array classes */
-
-               if (c->name->text[0] == '[')
-                       if (!(arraydesc = link_array(c)))
-                               return NULL;
-
-               if (c->flags & ACC_INTERFACE)
-                       c->index = interfaceindex++;
-               else
-                       c->index = super->index + 1;
-               
-               c->instancesize = super->instancesize;
-
-               vftbllength = supervftbllength = super->vftbl->vftbllength;
-               
-               c->finalizer = super->finalizer;
-       }
-       RT_TIMING_GET_TIME(time_resolving);
-
-
-       /* compute vftbl length */
-
-       for (i = 0; i < c->methodscount; i++) {
-               methodinfo *m = &(c->methods[i]);
-
-               if (!(m->flags & ACC_STATIC)) { /* is instance method */
-                       tc = super;
-
-                       while (tc) {
-                               s4 j;
-
-                               for (j = 0; j < tc->methodscount; j++) {
-                                       if (method_canoverwrite(m, &(tc->methods[j]))) {
-                                               if (tc->methods[j].flags & ACC_PRIVATE)
-                                                       goto notfoundvftblindex;
-
-                                               /* package-private methods in other packages */
-                                               /* must not be overridden                    */
-                                               /* (see Java Language Specification 8.4.8.1) */
-                                               if ( !(tc->methods[j].flags & (ACC_PUBLIC | ACC_PROTECTED)) 
-                                                        && !SAME_PACKAGE(c,tc) ) 
-                                               {
-                                                   goto notfoundvftblindex;
-                                               }
-
-                                               if (!linker_overwrite_method(&(tc->methods[j]), m, &worklist))
-                                                       return NULL;
-
-                                               goto foundvftblindex;
-                                       }
-                               }
-
-                               tc = tc->super;
-                       }
-
-               notfoundvftblindex:
-                       m->vftblindex = (vftbllength++);
-               foundvftblindex:
-                       ;
-               }
-       }
-       RT_TIMING_GET_TIME(time_compute_vftbl);
-
-
-       /* Check all interfaces of an abstract class (maybe be an
-          interface too) for unimplemented methods.  Such methods are
-          called miranda-methods and are marked with the ACC_MIRANDA
-          flag.  VMClass.getDeclaredMethods does not return such
-          methods. */
-
-       if (c->flags & ACC_ABSTRACT) {
-               classinfo  *ic;
-               methodinfo *im;
-               s4 abstractmethodscount;
-               s4 j;
-               s4 k;
-
-               abstractmethodscount = 0;
-
-               /* check all interfaces of the abstract class */
-
-               for (i = 0; i < c->interfacescount; i++) {
-                       ic = c->interfaces[i];
-
-                       for (j = 0; j < ic->methodscount; j++) {
-                               im = &(ic->methods[j]);
-
-                               /* skip `<clinit>' and `<init>' */
-
-                               if ((im->name == utf_clinit) || (im->name == utf_init))
-                                       continue;
-
-                               for (tc = c; tc != NULL; tc = tc->super) {
-                                       for (k = 0; k < tc->methodscount; k++) {
-                                               if (method_canoverwrite(im, &(tc->methods[k])))
-                                                       goto noabstractmethod;
-                                       }
-                               }
-
-                               abstractmethodscount++;
-
-                       noabstractmethod:
-                               ;
-                       }
-               }
-
-               if (abstractmethodscount > 0) {
-                       methodinfo *am;
-
-                       /* reallocate methods memory */
-
-                       c->methods = MREALLOC(c->methods, methodinfo, c->methodscount,
-                                                                 c->methodscount + abstractmethodscount);
-
-                       for (i = 0; i < c->interfacescount; i++) {
-                               ic = c->interfaces[i];
-
-                               for (j = 0; j < ic->methodscount; j++) {
-                                       im = &(ic->methods[j]);
-
-                                       /* skip `<clinit>' and `<init>' */
-
-                                       if ((im->name == utf_clinit) || (im->name == utf_init))
-                                               continue;
-
-                                       for (tc = c; tc != NULL; tc = tc->super) {
-                                               for (k = 0; k < tc->methodscount; k++) {
-                                                       if (method_canoverwrite(im, &(tc->methods[k])))
-                                                               goto noabstractmethod2;
-                                               }
-                                       }
-
-                                       /* Copy the method found into the new c->methods
-                                          array and tag it as miranda-method. */
-
-                                       am = &(c->methods[c->methodscount]);
-                                       c->methodscount++;
-
-                                       MCOPY(am, im, methodinfo, 1);
-
-                                       am->vftblindex  = (vftbllength++);
-                                       am->clazz       = c;
-                                       am->flags      |= ACC_MIRANDA;
-
-                               noabstractmethod2:
-                                       ;
-                               }
-                       }
-               }
-       }
-       RT_TIMING_GET_TIME(time_abstract);
-
-
-#if defined(ENABLE_STATISTICS)
-       if (opt_stat)
-               count_vftbl_len +=
-                       sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1));
-#endif
-
-       /* compute interfacetable length */
-
-       interfacetablelength = 0;
-
-       for (tc = c; tc != NULL; tc = tc->super) {
-               for (i = 0; i < tc->interfacescount; i++) {
-                       s4 h = class_highestinterface(tc->interfaces[i]) + 1;
-
-                       if (h > interfacetablelength)
-                               interfacetablelength = h;
-               }
-       }
-       RT_TIMING_GET_TIME(time_compute_iftbl);
-
-       /* allocate virtual function table */
-
-       v = (vftbl_t *) mem_alloc(sizeof(vftbl_t) +
-                                                         sizeof(methodptr) * (vftbllength - 1) +
-                                                         sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0)));
-       v = (vftbl_t *) (((methodptr *) v) +
-                                        (interfacetablelength - 1) * (interfacetablelength > 1));
-
-       c->vftbl                = v;
-       v->clazz                = c;
-       v->vftbllength          = vftbllength;
-       v->interfacetablelength = interfacetablelength;
-       v->arraydesc            = arraydesc;
-
-       /* store interface index in vftbl */
-
-       if (c->flags & ACC_INTERFACE)
-               v->baseval = -(c->index);
-
-       /* copy virtual function table of super class */
-
-       for (i = 0; i < supervftbllength; i++) 
-               v->table[i] = super->vftbl->table[i];
-
-       /* Fill the remaining vftbl slots with the AbstractMethodError
-          stub (all after the super class slots, because they are already
-          initialized). */
-
-       for (; i < vftbllength; i++) {
-#if defined(ENABLE_JIT)
-# if defined(ENABLE_INTRP)
-               if (opt_intrp)
-                       v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror;
-               else
-# endif
-                       v->table[i] = (methodptr) (ptrint) &asm_abstractmethoderror;
-#else
-               v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror;
-#endif
-       }
-
-       /* add method stubs into virtual function table */
-
-       for (i = 0; i < c->methodscount; i++) {
-               methodinfo *m = &(c->methods[i]);
-
-               assert(m->stubroutine == NULL);
-
-               /* Don't create a compiler stub for abstract methods as they
-                  throw an AbstractMethodError with the default stub in the
-                  vftbl.  This entry is simply copied by sub-classes. */
-
-               if (m->flags & ACC_ABSTRACT)
-                       continue;
-
-#if defined(ENABLE_JIT)
-# if defined(ENABLE_INTRP)
-               if (opt_intrp)
-                       m->stubroutine = intrp_createcompilerstub(m);
-               else
-#endif
-                       m->stubroutine = CompilerStub_generate(m);
-#else
-               m->stubroutine = intrp_createcompilerstub(m);
-#endif
-
-               /* static methods are not in the vftbl */
-
-               if (m->flags & ACC_STATIC)
-                       continue;
-
-               /* insert the stubroutine into the vftbl */
-
-               v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine;
-       }
-       RT_TIMING_GET_TIME(time_fill_vftbl);
-
-       /* compute instance size and offset of each field */
-       
-       for (i = 0; i < c->fieldscount; i++) {
-               s4 dsize;
-               fieldinfo *f = &(c->fields[i]);
-               
-               if (!(f->flags & ACC_STATIC)) {
-                       dsize = descriptor_typesize(f->parseddesc);
-                       c->instancesize = MEMORY_ALIGN(c->instancesize, dsize);
-                       f->offset = c->instancesize;
-                       c->instancesize += dsize;
-               }
-       }
-       RT_TIMING_GET_TIME(time_offsets);
-
-       /* initialize interfacetable and interfacevftbllength */
-
-       v->interfacevftbllength = MNEW(s4, interfacetablelength);
-
-#if defined(ENABLE_STATISTICS)
-       if (opt_stat)
-               count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength;
-#endif
-
-       for (i = 0; i < interfacetablelength; i++) {
-               v->interfacevftbllength[i] = 0;
-               v->interfacetable[-i] = NULL;
-       }
-
-       /* add interfaces */
-
-       for (tc = c; tc != NULL; tc = tc->super)
-               for (i = 0; i < tc->interfacescount; i++)
-                       if (!linker_addinterface(c, tc->interfaces[i]))
-                               return NULL;
-
-       RT_TIMING_GET_TIME(time_fill_iftbl);
-
-       /* add finalizer method (not for java.lang.Object) */
-
-       if (super) {
-               methodinfo *fi;
-
-               fi = class_findmethod(c, utf_finalize, utf_void__void);
-
-               if (fi)
-                       if (!(fi->flags & ACC_STATIC))
-                               c->finalizer = fi;
-       }
-       RT_TIMING_GET_TIME(time_finalizer);
-
-       /* final tasks */
-
-       linker_compute_subclasses(c);
-
-       RT_TIMING_GET_TIME(time_subclasses);
-
-       /* revert the linking state and class is linked */
-
-       c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED;
-
-       /* check worklist */
-
-       /* XXX must this also be done in case of exception? */
-
-       while (worklist != NULL) {
-               method_worklist *wi = worklist;
-
-               worklist = worklist->next;
-
-               INLINELOG( printf("MUST BE RECOMPILED: "); method_println(wi->m); );
-               jit_invalidate_code(wi->m);
-
-               /* XXX put worklist into dump memory? */
-               FREE(wi, method_worklist);
-       }
-
-       RT_TIMING_TIME_DIFF(time_start        ,time_resolving    ,RT_TIMING_LINK_RESOLVE);
-       RT_TIMING_TIME_DIFF(time_resolving    ,time_compute_vftbl,RT_TIMING_LINK_C_VFTBL);
-       RT_TIMING_TIME_DIFF(time_compute_vftbl,time_abstract     ,RT_TIMING_LINK_ABSTRACT);
-       RT_TIMING_TIME_DIFF(time_abstract     ,time_compute_iftbl,RT_TIMING_LINK_C_IFTBL);
-       RT_TIMING_TIME_DIFF(time_compute_iftbl,time_fill_vftbl   ,RT_TIMING_LINK_F_VFTBL);
-       RT_TIMING_TIME_DIFF(time_fill_vftbl   ,time_offsets      ,RT_TIMING_LINK_OFFSETS);
-       RT_TIMING_TIME_DIFF(time_offsets      ,time_fill_iftbl   ,RT_TIMING_LINK_F_IFTBL);
-       RT_TIMING_TIME_DIFF(time_fill_iftbl   ,time_finalizer    ,RT_TIMING_LINK_FINALIZER);
-       RT_TIMING_TIME_DIFF(time_finalizer    ,time_subclasses   ,RT_TIMING_LINK_SUBCLASS);
-
-       /* just return c to show that we didn't had a problem */
-
-       return c;
-}
-
-
-/* link_array ******************************************************************
-
-   This function is called by link_class to create the arraydescriptor
-   for an array class.
-
-   This function returns NULL if the array cannot be linked because
-   the component type has not been linked yet.
-
-*******************************************************************************/
-
-static arraydescriptor *link_array(classinfo *c)
-{
-       classinfo       *comp;
-       s4               namelen;
-       arraydescriptor *desc;
-       vftbl_t         *compvftbl;
-       utf             *u;
-
-       comp = NULL;
-       namelen = c->name->blength;
-
-       /* Check the component type */
-
-       switch (c->name->text[1]) {
-       case '[':
-               /* c is an array of arrays. */
-               u = utf_new(c->name->text + 1, namelen - 1);
-               if (!(comp = load_class_from_classloader(u, c->classloader)))
-                       return NULL;
-               break;
-
-       case 'L':
-               /* c is an array of objects. */
-               u = utf_new(c->name->text + 2, namelen - 3);
-               if (!(comp = load_class_from_classloader(u, c->classloader)))
-                       return NULL;
-               break;
-       }
-
-       /* If the component type has not been linked, link it now */
-
-       assert(!comp || (comp->state & CLASS_LOADED));
-
-       if (comp && !(comp->state & CLASS_LINKED))
-               if (!link_class(comp))
-                       return NULL;
-
-       /* Allocate the arraydescriptor */
-
-       desc = NEW(arraydescriptor);
-
-       if (comp) {
-               /* c is an array of references */
-               desc->arraytype = ARRAYTYPE_OBJECT;
-               desc->componentsize = sizeof(void*);
-               desc->dataoffset = OFFSET(java_objectarray_t, data);
-               
-               compvftbl = comp->vftbl;
-
-               if (!compvftbl) {
-                       log_text("Component class has no vftbl");
-                       assert(0);
-               }
-
-               desc->componentvftbl = compvftbl;
-               
-               if (compvftbl->arraydesc) {
-                       desc->elementvftbl = compvftbl->arraydesc->elementvftbl;
-
-                       if (compvftbl->arraydesc->dimension >= 255) {
-                               log_text("Creating array of dimension >255");
-                               assert(0);
-                       }
-
-                       desc->dimension = compvftbl->arraydesc->dimension + 1;
-                       desc->elementtype = compvftbl->arraydesc->elementtype;
-
-               } else {
-                       desc->elementvftbl = compvftbl;
-                       desc->dimension = 1;
-                       desc->elementtype = ARRAYTYPE_OBJECT;
-               }
-
-       } else {
-               /* c is an array of a primitive type */
-               switch (c->name->text[1]) {
-               case 'Z':
-                       desc->arraytype = ARRAYTYPE_BOOLEAN;
-                       desc->dataoffset = OFFSET(java_booleanarray_t,data);
-                       desc->componentsize = sizeof(u1);
-                       break;
-
-               case 'B':
-                       desc->arraytype = ARRAYTYPE_BYTE;
-                       desc->dataoffset = OFFSET(java_bytearray_t,data);
-                       desc->componentsize = sizeof(u1);
-                       break;
-
-               case 'C':
-                       desc->arraytype = ARRAYTYPE_CHAR;
-                       desc->dataoffset = OFFSET(java_chararray_t,data);
-                       desc->componentsize = sizeof(u2);
-                       break;
-
-               case 'D':
-                       desc->arraytype = ARRAYTYPE_DOUBLE;
-                       desc->dataoffset = OFFSET(java_doublearray_t,data);
-                       desc->componentsize = sizeof(double);
-                       break;
-
-               case 'F':
-                       desc->arraytype = ARRAYTYPE_FLOAT;
-                       desc->dataoffset = OFFSET(java_floatarray_t,data);
-                       desc->componentsize = sizeof(float);
-                       break;
-
-               case 'I':
-                       desc->arraytype = ARRAYTYPE_INT;
-                       desc->dataoffset = OFFSET(java_intarray_t,data);
-                       desc->componentsize = sizeof(s4);
-                       break;
-
-               case 'J':
-                       desc->arraytype = ARRAYTYPE_LONG;
-                       desc->dataoffset = OFFSET(java_longarray_t,data);
-                       desc->componentsize = sizeof(s8);
-                       break;
-
-               case 'S':
-                       desc->arraytype = ARRAYTYPE_SHORT;
-                       desc->dataoffset = OFFSET(java_shortarray_t,data);
-                       desc->componentsize = sizeof(s2);
-                       break;
-
-               default:
-                       exceptions_throw_noclassdeffounderror(c->name);
-                       return NULL;
-               }
-               
-               desc->componentvftbl = NULL;
-               desc->elementvftbl = NULL;
-               desc->dimension = 1;
-               desc->elementtype = desc->arraytype;
-       }
-
-       return desc;
-}
-
-
-/* linker_compute_subclasses ***************************************************
-
-   XXX
-
-   ATTENTION: DO NOT REMOVE ANY OF THE LOCKING MECHANISMS BELOW:
-   This function needs to take the class renumber lock and stop the
-   world during class renumbering. The lock is used in C code which
-   is not that performance critical. Whereas JIT code uses critical
-   sections to atomically access the class values.
-
-*******************************************************************************/
-
-static void linker_compute_subclasses(classinfo *c)
-{
-       Mutex_lock(linker_classrenumber_mutex);
-
-       if (!(c->flags & ACC_INTERFACE)) {
-               c->nextsub = NULL;
-               c->sub     = NULL;
-       }
-
-       if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) {
-               c->nextsub    = c->super->sub;
-               c->super->sub = c;
-       }
-
-       classvalue = 0;
-
-       /* compute class values */
-
-       linker_compute_class_values(class_java_lang_Object);
-
-       Mutex_unlock(linker_classrenumber_mutex);
-}
-
-
-/* linker_compute_class_values *************************************************
-
-   XXX
-
-*******************************************************************************/
-
-static void linker_compute_class_values(classinfo *c)
-{
-       classinfo *subs;
-
-       c->vftbl->baseval = ++classvalue;
-
-       subs = c->sub;
-
-       while (subs) {
-               linker_compute_class_values(subs);
-
-               subs = subs->nextsub;
-       }
-
-       c->vftbl->diffval = classvalue - c->vftbl->baseval;
-}
-
-
-/* linker_addinterface *********************************************************
-
-   Is needed by link_class for adding a VTBL to a class. All
-   interfaces implemented by ic are added as well.
-
-   RETURN VALUE:
-      true.........everything ok
-         false........an exception has been thrown
-
-*******************************************************************************/
-
-static bool linker_addinterface(classinfo *c, classinfo *ic)
-{
-       s4          j, k;
-       vftbl_t    *v;
-       s4          i;
-       classinfo  *sc;
-       methodinfo *m;
-
-       v = c->vftbl;
-       i = ic->index;
-
-       if (i >= v->interfacetablelength)
-               vm_abort("Internal error: interfacetable overflow");
-
-       /* if this interface has already been added, return immediately */
-
-       if (v->interfacetable[-i] != NULL)
-               return true;
-
-       if (ic->methodscount == 0) {  /* fake entry needed for subtype test */
-               v->interfacevftbllength[i] = 1;
-               v->interfacetable[-i]      = MNEW(methodptr, 1);
-               v->interfacetable[-i][0]   = NULL;
-       }
-       else {
-               v->interfacevftbllength[i] = ic->methodscount;
-               v->interfacetable[-i]      = MNEW(methodptr, ic->methodscount);
-
-#if defined(ENABLE_STATISTICS)
-               if (opt_stat)
-                       count_vftbl_len += sizeof(methodptr) *
-                               (ic->methodscount + (ic->methodscount == 0));
-#endif
-
-               for (j = 0; j < ic->methodscount; j++) {
-                       for (sc = c; sc != NULL; sc = sc->super) {
-                               for (k = 0; k < sc->methodscount; k++) {
-                                       m = &(sc->methods[k]);
-
-                                       if (method_canoverwrite(m, &(ic->methods[j]))) {
-                                               /* method m overwrites the (abstract) method */
-#if defined(ENABLE_VERIFIER)
-                                               /* Add loading constraints (for the more
-                                                  general types of the method
-                                                  ic->methods[j]).  */
-                                               if (!classcache_add_constraints_for_params(
-                                                                       c->classloader, ic->classloader,
-                                                                       &(ic->methods[j])))
-                                               {
-                                                       return false;
-                                               }
-#endif
-
-                                               /* XXX taken from gcj */
-                                               /* check for ACC_STATIC: IncompatibleClassChangeError */
-
-                                               /* check for !ACC_PUBLIC: IllegalAccessError */
-
-                                               /* check for ACC_ABSTRACT: AbstracMethodError,
-                                                  not sure about that one */
-
-                                               v->interfacetable[-i][j] = v->table[m->vftblindex];
-                                               goto foundmethod;
-                                       }
-                               }
-                       }
-
-                       /* If no method was found, insert the AbstractMethodError
-                          stub. */
-
-#if defined(ENABLE_JIT)
-# if defined(ENABLE_INTRP)
-                       if (opt_intrp)
-                               v->interfacetable[-i][j] =
-                                       (methodptr) (ptrint) &intrp_asm_abstractmethoderror;
-                       else
-# endif
-                               v->interfacetable[-i][j] =
-                                       (methodptr) (ptrint) &asm_abstractmethoderror;
-#else
-                       v->interfacetable[-i][j] =
-                               (methodptr) (ptrint) &intrp_asm_abstractmethoderror;
-#endif
-
-               foundmethod:
-                       ;
-               }
-       }
-
-       /* add superinterfaces of this interface */
-
-       for (j = 0; j < ic->interfacescount; j++)
-               if (!linker_addinterface(c, ic->interfaces[j]))
-                       return false;
-
-       /* everything ok */
-
-       return true;
-}
-
-
-/* class_highestinterface ******************************************************
-
-   Used by the function link_class to determine the amount of memory
-   needed for the interface table.
-
-*******************************************************************************/
-
-static s4 class_highestinterface(classinfo *c)
-{
-       s4 h;
-       s4 h2;
-       s4 i;
-       
-    /* check for ACC_INTERFACE bit already done in link_class_intern */
-
-    h = c->index;
-
-       for (i = 0; i < c->interfacescount; i++) {
-               h2 = class_highestinterface(c->interfaces[i]);
-
-               if (h2 > h)
-                       h = h2;
-       }
-
-       return 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/linker.cpp b/src/vm/linker.cpp
new file mode 100644 (file)
index 0000000..8091650
--- /dev/null
@@ -0,0 +1,1326 @@
+/* src/vm/linker.c - class linker 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 "vm/types.h"
+
+#include "mm/memory.h"
+
+#include "native/native.hpp"
+
+#include "threads/lock.hpp"
+#include "threads/mutex.hpp"
+
+#include "toolbox/logging.h"
+
+#include "vm/access.hpp"
+#include "vm/array.hpp"
+#include "vm/class.hpp"
+#include "vm/classcache.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/globals.hpp"
+#include "vm/loader.hpp"
+#include "vm/options.h"
+#include "vm/primitive.hpp"
+#include "vm/rt-timing.h"
+#include "vm/string.hpp"
+#include "vm/vm.hpp"
+
+#include "vm/jit/asmpart.h"
+#include "vm/jit/stubs.hpp"
+
+
+/* debugging macros ***********************************************************/
+
+#if !defined(NDEBUG)
+# define TRACELINKCLASS(c) \
+    do { \
+        if (opt_TraceLinkClass) { \
+            log_start(); \
+            log_print("[Linking "); \
+            class_print((c)); \
+            log_print("]"); \
+            log_finish(); \
+        } \
+    } while (0)
+#else
+# define TRACELINKCLASS(c)
+#endif
+
+
+/* #include "vm/resolve.hpp" */
+/* copied prototype to avoid bootstrapping problem: */
+classinfo *resolve_classref_or_classinfo_eager(classref_or_classinfo cls, bool checkaccess);
+
+#if defined(ENABLE_STATISTICS)
+# include "vm/statistics.h"
+#endif
+
+#if !defined(NDEBUG) && defined(ENABLE_INLINING)
+#define INLINELOG(code)  do { if (opt_TraceInlining) { code } } while (0)
+#else
+#define INLINELOG(code)
+#endif
+
+
+/* global variables ***********************************************************/
+
+static s4 interfaceindex;       /* sequential numbering of interfaces         */
+static s4 classvalue;
+
+Mutex *linker_classrenumber_mutex;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* private functions **********************************************************/
+
+static classinfo *link_class_intern(classinfo *c);
+static arraydescriptor *link_array(classinfo *c);
+static void linker_compute_class_values(classinfo *c);
+static void linker_compute_subclasses(classinfo *c);
+static bool linker_addinterface(classinfo *c, classinfo *ic);
+static s4 class_highestinterface(classinfo *c);
+
+
+/* linker_init *****************************************************************
+
+   Initializes the linker subsystem and links classes required for the
+   primitive table.
+
+*******************************************************************************/
+
+void linker_preinit(void)
+{
+       TRACESUBSYSTEMINITIALIZATION("linker_preinit");
+
+       /* Reset interface index. */
+
+       interfaceindex = 0;
+
+#if defined(ENABLE_THREADS)
+       /* create the global mutex */
+
+       linker_classrenumber_mutex = new Mutex();
+#endif
+
+       /* Link the most basic classes. */
+
+       if (!link_class(class_java_lang_Object))
+               vm_abort("linker_preinit: linking java/lang/Object failed");
+
+#if defined(ENABLE_JAVASE)
+       if (!link_class(class_java_lang_Cloneable))
+               vm_abort("linker_preinit: linking java/lang/Cloneable failed");
+
+       if (!link_class(class_java_io_Serializable))
+               vm_abort("linker_preinit: linking java/io/Serializable failed");
+#endif
+}
+
+
+/* linker_init *****************************************************************
+
+   Links all classes required in the VM.
+
+*******************************************************************************/
+
+void linker_init(void)
+{
+       TRACESUBSYSTEMINITIALIZATION("linker_init");
+
+       /* Link java.lang.Class as first class of the system, because we
+       need it's vftbl for all other classes so we can use a class as
+       object. */
+
+       if (!link_class(class_java_lang_Class))
+               vm_abort("linker_init: linking java/lang/Class failed");
+
+       /* Now set the header.vftbl of all classes which were created
+       before java.lang.Class was linked. */
+
+       class_postset_header_vftbl();
+
+       /* Link primitive-type wrapping classes. */
+
+#if defined(ENABLE_JAVASE)
+       if (!link_class(class_java_lang_Void))
+               vm_abort("linker_init: linking failed");
+#endif
+
+       if (!link_class(class_java_lang_Boolean))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_Byte))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_Character))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_Short))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_Integer))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_Long))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_Float))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_Double))
+               vm_abort("linker_init: linking failed");
+
+       /* Link important system classes. */
+
+       if (!link_class(class_java_lang_String))
+               vm_abort("linker_init: linking java/lang/String failed");
+
+#if defined(ENABLE_JAVASE)
+       if (!link_class(class_java_lang_ClassLoader))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_SecurityManager))
+               vm_abort("linker_init: linking failed");
+#endif
+
+       if (!link_class(class_java_lang_System))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_Thread))
+               vm_abort("linker_init: linking failed");
+
+#if defined(ENABLE_JAVASE)
+       if (!link_class(class_java_lang_ThreadGroup))
+               vm_abort("linker_init: linking failed");
+#endif
+
+       if (!link_class(class_java_lang_Throwable))
+               vm_abort("linker_init: linking failed");
+
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+       if (!link_class(class_java_lang_VMSystem))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_VMThread))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_VMThrowable))
+               vm_abort("linker_init: linking failed");
+#endif
+
+       /* Important system exceptions. */
+
+       if (!link_class(class_java_lang_Exception))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_ClassNotFoundException))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_RuntimeException))
+               vm_abort("linker_init: linking failed");
+
+       /* some classes which may be used more often */
+
+#if defined(ENABLE_JAVASE)
+       if (!link_class(class_java_lang_StackTraceElement))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_reflect_Constructor))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_reflect_Field))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_reflect_Method))
+               vm_abort("linker_init: linking failed");
+
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+       if (!link_class(class_java_lang_reflect_VMConstructor))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_reflect_VMField))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_lang_reflect_VMMethod))
+               vm_abort("linker_init: linking failed");
+# endif
+
+       if (!link_class(class_java_security_PrivilegedAction))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_util_Vector))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_java_util_HashMap))
+               vm_abort("linker_init: linking failed");
+
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+       if (!link_class(class_sun_misc_Signal))
+               vm_abort("linker_init: linking failed");
+
+       if (!link_class(class_sun_reflect_MagicAccessorImpl))
+               vm_abort("linker_init: linking failed");
+# endif
+
+       if (!link_class(arrayclass_java_lang_Object))
+               vm_abort("linker_init: linking failed");
+#endif
+
+
+       /* create pseudo classes used by the typechecker */
+
+    /* pseudo class for Arraystubs (extends java.lang.Object) */
+
+       pseudo_class_Arraystub                   =
+               class_create_classinfo(utf_new_char("$ARRAYSTUB$"));
+       pseudo_class_Arraystub->state           |= CLASS_LOADED;
+       pseudo_class_Arraystub->super            = class_java_lang_Object;
+
+#if defined(ENABLE_JAVASE)
+
+       pseudo_class_Arraystub->interfacescount  = 2;
+       pseudo_class_Arraystub->interfaces       = MNEW(classinfo*, 2);
+       pseudo_class_Arraystub->interfaces[0]    = class_java_lang_Cloneable;
+       pseudo_class_Arraystub->interfaces[1]    = class_java_io_Serializable;
+
+#elif defined(ENABLE_JAVAME_CLDC1_1)
+
+       pseudo_class_Arraystub->interfacescount    = 0;
+       pseudo_class_Arraystub->interfaces         = NULL;
+
+#else
+# error unknown Java configuration
+#endif
+
+       if (!classcache_store_unique(pseudo_class_Arraystub))
+               vm_abort("linker_init: could not cache pseudo_class_Arraystub");
+
+       if (!link_class(pseudo_class_Arraystub))
+               vm_abort("linker_init: linking pseudo_class_Arraystub failed");
+
+       /* pseudo class representing the null type */
+
+       pseudo_class_Null         = class_create_classinfo(utf_new_char("$NULL$"));
+       pseudo_class_Null->state |= CLASS_LOADED;
+       pseudo_class_Null->super  = class_java_lang_Object;
+
+       if (!classcache_store_unique(pseudo_class_Null))
+               vm_abort("linker_init: could not cache pseudo_class_Null");
+
+       if (!link_class(pseudo_class_Null))
+               vm_abort("linker_init: linking failed");
+
+       /* pseudo class representing new uninitialized objects */
+    
+       pseudo_class_New         = class_create_classinfo(utf_new_char("$NEW$"));
+       pseudo_class_New->state |= CLASS_LOADED;
+       pseudo_class_New->state |= CLASS_LINKED; /* XXX is this allright? */
+       pseudo_class_New->super  = class_java_lang_Object;
+
+       if (!classcache_store_unique(pseudo_class_New))
+               vm_abort("linker_init: could not cache pseudo_class_New");
+
+       /* Correct vftbl-entries (retarded loading and linking of class
+          java/lang/String). */
+
+       stringtable_update();
+}
+
+
+/* link_class ******************************************************************
+
+   Wrapper function for link_class_intern to ease monitor enter/exit
+   and exception handling.
+
+*******************************************************************************/
+
+classinfo *link_class(classinfo *c)
+{
+       classinfo *r;
+#if defined(ENABLE_RT_TIMING)
+       struct timespec time_start, time_end;
+#endif
+
+       RT_TIMING_GET_TIME(time_start);
+
+       if (c == NULL) {
+               exceptions_throw_nullpointerexception();
+               return NULL;
+       }
+
+       LOCK_MONITOR_ENTER(c);
+
+       /* Maybe the class is currently linking or is already linked.*/
+
+       if ((c->state & CLASS_LINKING) || (c->state & CLASS_LINKED)) {
+               LOCK_MONITOR_EXIT(c);
+
+               return c;
+       }
+
+#if defined(ENABLE_STATISTICS)
+       /* measure time */
+
+       if (opt_getcompilingtime)
+               compilingtime_stop();
+
+       if (opt_getloadingtime)
+               loadingtime_start();
+#endif
+
+       /* call the internal function */
+
+       r = link_class_intern(c);
+
+       /* If return value is NULL, we had a problem and the class is not
+          linked. */
+
+       if (r == NULL)
+               c->state &= ~CLASS_LINKING;
+
+#if defined(ENABLE_STATISTICS)
+       /* measure time */
+
+       if (opt_getloadingtime)
+               loadingtime_stop();
+
+       if (opt_getcompilingtime)
+               compilingtime_start();
+#endif
+
+       LOCK_MONITOR_EXIT(c);
+
+       RT_TIMING_GET_TIME(time_end);
+
+       RT_TIMING_TIME_DIFF(time_start,time_end,RT_TIMING_LINK_TOTAL);
+
+       return r;
+}
+
+
+/* linker_overwrite_method *****************************************************
+
+   Overwrite a method with another one, update method flags and check
+   assumptions.
+
+   IN:
+      mg................the general method being overwritten
+         ms................the overwriting (more specialized) method
+         wl................worklist where to add invalidated methods
+
+   RETURN VALUE:
+      true..............everything ok
+         false.............an exception has been thrown
+
+*******************************************************************************/
+
+static bool linker_overwrite_method(methodinfo *mg,
+                                                                       methodinfo *ms,
+                                                                       method_worklist **wl)
+{
+       classinfo *cg;
+       classinfo *cs;
+
+       cg = mg->clazz;
+       cs = ms->clazz;
+
+       /* overriding a final method is illegal */
+
+       if (mg->flags & ACC_FINAL) {
+               exceptions_throw_verifyerror(mg, "Overriding final method");
+               return false;
+       }
+
+       /* method ms overwrites method mg */
+
+#if defined(ENABLE_VERIFIER)
+       /* Add loading constraints (for the more general types of method mg). */
+       /* Not for <init>, as it is not invoked virtually.                    */
+
+       if ((ms->name != utf_init)
+                       && !classcache_add_constraints_for_params(
+                               cs->classloader, cg->classloader, mg))
+       {
+               return false;
+       }
+#endif
+
+       /* inherit the vftbl index, and record the overwriting */
+
+       ms->vftblindex = mg->vftblindex;
+       ms->overwrites = mg;
+
+       /* update flags and check assumptions */
+       /* <init> methods are a special case, as they are never dispatched dynamically */
+
+       if ((ms->flags & ACC_METHOD_IMPLEMENTED) && ms->name != utf_init) {
+               do {
+
+#if defined(ENABLE_TLH)
+                       if (mg->flags & ACC_METHOD_MONOMORPHY_USED) {
+                               printf("%s/%s is evil! the siner is %s/%s\n", mg->clazz->name->text, mg->name->text,
+                                       ms->clazz->name->text, ms->name->text);
+                               ms->flags |= ACC_METHOD_PARENT_MONOMORPHY_USED;                                 
+                       }
+#endif
+
+                       if (mg->flags & ACC_METHOD_IMPLEMENTED) {
+                               /* this adds another implementation */
+
+                               mg->flags &= ~ACC_METHOD_MONOMORPHIC;
+
+                               INLINELOG( printf("becomes polymorphic: "); method_println(mg); );
+
+                               method_break_assumption_monomorphic(mg, wl);
+                       }
+                       else {
+                               /* this is the first implementation */
+
+                               mg->flags |= ACC_METHOD_IMPLEMENTED;
+
+                               INLINELOG( printf("becomes implemented: "); method_println(mg); );
+                       }
+
+                       ms = mg;
+                       mg = mg->overwrites;
+               } while (mg != NULL);
+       }
+
+       return true;
+}
+
+
+/* link_class_intern ***********************************************************
+
+   Tries to link a class. The function calculates the length in bytes
+   that an instance of this class requires as well as the VTBL for
+   methods and interface methods.
+       
+*******************************************************************************/
+
+static classinfo *link_class_intern(classinfo *c)
+{
+       classinfo *super;             /* super class                              */
+       classinfo *tc;                /* temporary class variable                 */
+       s4 supervftbllength;          /* vftbllegnth of super class               */
+       s4 vftbllength;               /* vftbllength of current class             */
+       s4 interfacetablelength;      /* interface table length                   */
+       vftbl_t *v;                   /* vftbl of current class                   */
+       s4 i;                         /* interface/method/field counter           */
+       arraydescriptor *arraydesc;   /* descriptor for array classes             */
+       method_worklist *worklist;    /* worklist for recompilation               */
+#if defined(ENABLE_RT_TIMING)
+       struct timespec time_start, time_resolving, time_compute_vftbl,
+                                       time_abstract, time_compute_iftbl, time_fill_vftbl,
+                                       time_offsets, time_fill_iftbl, time_finalizer,
+                                       time_subclasses;
+#endif
+
+       RT_TIMING_GET_TIME(time_start);
+
+       TRACELINKCLASS(c);
+
+       /* the class must be loaded */
+
+       /* XXX should this be a specific exception? */
+       assert(c->state & CLASS_LOADED);
+
+       /* This is check in link_class. */
+
+       assert(!(c->state & CLASS_LINKED));
+
+       /* cache the self-reference of this class                          */
+       /* we do this for cases where the defining loader of the class     */
+       /* has not yet been recorded as an initiating loader for the class */
+       /* this is needed so subsequent code can assume that self-refs     */
+       /* will always resolve lazily                                      */
+       /* No need to do it for the bootloader - it is always registered   */
+       /* as initiating loader for the classes it loads.                  */
+       if (c->classloader)
+               classcache_store(c->classloader,c,false);
+
+       /* this class is currently linking */
+
+       c->state |= CLASS_LINKING;
+
+       arraydesc = NULL;
+       worklist = NULL;
+
+       /* Link the super interfaces. */
+
+       for (i = 0; i < c->interfacescount; i++) {
+               tc = c->interfaces[i];
+
+               if (!(tc->state & CLASS_LINKED))
+                       if (!link_class(tc))
+                               return NULL;
+       }
+       
+       /* check super class */
+
+       super = NULL;
+
+       /* Check for java/lang/Object. */
+
+       if (c->super == NULL) {
+               c->index = 0;
+               c->instancesize = sizeof(java_object_t);
+               
+               vftbllength = supervftbllength = 0;
+
+               c->finalizer = NULL;
+       }
+       else {
+               /* Get super class. */
+
+               super = c->super;
+
+               /* Link the super class if necessary. */
+               
+               if (!(super->state & CLASS_LINKED))
+                       if (!link_class(super))
+                               return NULL;
+
+               /* OR the ACC_CLASS_HAS_POINTERS and the ACC_CLASS_REFERENCE_*
+                  flags. */
+
+               c->flags |= (super->flags &
+                                        (ACC_CLASS_HAS_POINTERS | ACC_CLASS_REFERENCE_MASK));
+
+               /* handle array classes */
+
+               if (c->name->text[0] == '[')
+                       if (!(arraydesc = link_array(c)))
+                               return NULL;
+
+               if (c->flags & ACC_INTERFACE)
+                       c->index = interfaceindex++;
+               else
+                       c->index = super->index + 1;
+               
+               c->instancesize = super->instancesize;
+
+               vftbllength = supervftbllength = super->vftbl->vftbllength;
+               
+               c->finalizer = super->finalizer;
+       }
+       RT_TIMING_GET_TIME(time_resolving);
+
+
+       /* compute vftbl length */
+
+       for (i = 0; i < c->methodscount; i++) {
+               methodinfo *m = &(c->methods[i]);
+
+               if (!(m->flags & ACC_STATIC)) { /* is instance method */
+                       tc = super;
+
+                       while (tc) {
+                               s4 j;
+
+                               for (j = 0; j < tc->methodscount; j++) {
+                                       if (method_canoverwrite(m, &(tc->methods[j]))) {
+                                               if (tc->methods[j].flags & ACC_PRIVATE)
+                                                       goto notfoundvftblindex;
+
+                                               /* package-private methods in other packages */
+                                               /* must not be overridden                    */
+                                               /* (see Java Language Specification 8.4.8.1) */
+                                               if ( !(tc->methods[j].flags & (ACC_PUBLIC | ACC_PROTECTED)) 
+                                                        && !SAME_PACKAGE(c,tc) ) 
+                                               {
+                                                   goto notfoundvftblindex;
+                                               }
+
+                                               if (!linker_overwrite_method(&(tc->methods[j]), m, &worklist))
+                                                       return NULL;
+
+                                               goto foundvftblindex;
+                                       }
+                               }
+
+                               tc = tc->super;
+                       }
+
+               notfoundvftblindex:
+                       m->vftblindex = (vftbllength++);
+               foundvftblindex:
+                       ;
+               }
+       }
+       RT_TIMING_GET_TIME(time_compute_vftbl);
+
+
+       /* Check all interfaces of an abstract class (maybe be an
+          interface too) for unimplemented methods.  Such methods are
+          called miranda-methods and are marked with the ACC_MIRANDA
+          flag.  VMClass.getDeclaredMethods does not return such
+          methods. */
+
+       if (c->flags & ACC_ABSTRACT) {
+               classinfo  *ic;
+               methodinfo *im;
+               s4 abstractmethodscount;
+               s4 j;
+               s4 k;
+
+               abstractmethodscount = 0;
+
+               /* check all interfaces of the abstract class */
+
+               for (i = 0; i < c->interfacescount; i++) {
+                       ic = c->interfaces[i];
+
+                       for (j = 0; j < ic->methodscount; j++) {
+                               im = &(ic->methods[j]);
+
+                               /* skip `<clinit>' and `<init>' */
+
+                               if ((im->name == utf_clinit) || (im->name == utf_init))
+                                       continue;
+
+                               for (tc = c; tc != NULL; tc = tc->super) {
+                                       for (k = 0; k < tc->methodscount; k++) {
+                                               if (method_canoverwrite(im, &(tc->methods[k])))
+                                                       goto noabstractmethod;
+                                       }
+                               }
+
+                               abstractmethodscount++;
+
+                       noabstractmethod:
+                               ;
+                       }
+               }
+
+               if (abstractmethodscount > 0) {
+                       methodinfo *am;
+
+                       /* reallocate methods memory */
+
+                       c->methods = (methodinfo*) MREALLOC(c->methods, methodinfo, c->methodscount,
+                                                                 c->methodscount + abstractmethodscount);
+
+                       for (i = 0; i < c->interfacescount; i++) {
+                               ic = c->interfaces[i];
+
+                               for (j = 0; j < ic->methodscount; j++) {
+                                       im = &(ic->methods[j]);
+
+                                       /* skip `<clinit>' and `<init>' */
+
+                                       if ((im->name == utf_clinit) || (im->name == utf_init))
+                                               continue;
+
+                                       for (tc = c; tc != NULL; tc = tc->super) {
+                                               for (k = 0; k < tc->methodscount; k++) {
+                                                       if (method_canoverwrite(im, &(tc->methods[k])))
+                                                               goto noabstractmethod2;
+                                               }
+                                       }
+
+                                       /* Copy the method found into the new c->methods
+                                          array and tag it as miranda-method. */
+
+                                       am = &(c->methods[c->methodscount]);
+                                       c->methodscount++;
+
+                                       MCOPY(am, im, methodinfo, 1);
+
+                                       am->vftblindex  = (vftbllength++);
+                                       am->clazz       = c;
+                                       am->flags      |= ACC_MIRANDA;
+
+                               noabstractmethod2:
+                                       ;
+                               }
+                       }
+               }
+       }
+       RT_TIMING_GET_TIME(time_abstract);
+
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               count_vftbl_len +=
+                       sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1));
+#endif
+
+       /* compute interfacetable length */
+
+       interfacetablelength = 0;
+
+       for (tc = c; tc != NULL; tc = tc->super) {
+               for (i = 0; i < tc->interfacescount; i++) {
+                       s4 h = class_highestinterface(tc->interfaces[i]) + 1;
+
+                       if (h > interfacetablelength)
+                               interfacetablelength = h;
+               }
+       }
+       RT_TIMING_GET_TIME(time_compute_iftbl);
+
+       /* allocate virtual function table */
+
+       v = (vftbl_t *) mem_alloc(sizeof(vftbl_t) +
+                                                         sizeof(methodptr) * (vftbllength - 1) +
+                                                         sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0)));
+       v = (vftbl_t *) (((methodptr *) v) +
+                                        (interfacetablelength - 1) * (interfacetablelength > 1));
+
+       c->vftbl                = v;
+       v->clazz                = c;
+       v->vftbllength          = vftbllength;
+       v->interfacetablelength = interfacetablelength;
+       v->arraydesc            = arraydesc;
+
+       /* store interface index in vftbl */
+
+       if (c->flags & ACC_INTERFACE)
+               v->baseval = -(c->index);
+
+       /* copy virtual function table of super class */
+
+       for (i = 0; i < supervftbllength; i++) 
+               v->table[i] = super->vftbl->table[i];
+
+       /* Fill the remaining vftbl slots with the AbstractMethodError
+          stub (all after the super class slots, because they are already
+          initialized). */
+
+       for (; i < vftbllength; i++) {
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+               if (opt_intrp)
+                       v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror;
+               else
+# endif
+                       v->table[i] = (methodptr) (ptrint) &asm_abstractmethoderror;
+#else
+               v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror;
+#endif
+       }
+
+       /* add method stubs into virtual function table */
+
+       for (i = 0; i < c->methodscount; i++) {
+               methodinfo *m = &(c->methods[i]);
+
+               assert(m->stubroutine == NULL);
+
+               /* Don't create a compiler stub for abstract methods as they
+                  throw an AbstractMethodError with the default stub in the
+                  vftbl.  This entry is simply copied by sub-classes. */
+
+               if (m->flags & ACC_ABSTRACT)
+                       continue;
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+               if (opt_intrp)
+                       m->stubroutine = intrp_createcompilerstub(m);
+               else
+#endif
+                       m->stubroutine = (u1*) CompilerStub::generate(m);
+#else
+               m->stubroutine = intrp_createcompilerstub(m);
+#endif
+
+               /* static methods are not in the vftbl */
+
+               if (m->flags & ACC_STATIC)
+                       continue;
+
+               /* insert the stubroutine into the vftbl */
+
+               v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine;
+       }
+       RT_TIMING_GET_TIME(time_fill_vftbl);
+
+       /* compute instance size and offset of each field */
+       
+       for (i = 0; i < c->fieldscount; i++) {
+               s4 dsize;
+               fieldinfo *f = &(c->fields[i]);
+               
+               if (!(f->flags & ACC_STATIC)) {
+                       dsize = descriptor_typesize(f->parseddesc);
+                       c->instancesize = MEMORY_ALIGN(c->instancesize, dsize);
+                       f->offset = c->instancesize;
+                       c->instancesize += dsize;
+               }
+       }
+       RT_TIMING_GET_TIME(time_offsets);
+
+       /* initialize interfacetable and interfacevftbllength */
+
+       v->interfacevftbllength = MNEW(s4, interfacetablelength);
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength;
+#endif
+
+       for (i = 0; i < interfacetablelength; i++) {
+               v->interfacevftbllength[i] = 0;
+               v->interfacetable[-i] = NULL;
+       }
+
+       /* add interfaces */
+
+       for (tc = c; tc != NULL; tc = tc->super)
+               for (i = 0; i < tc->interfacescount; i++)
+                       if (!linker_addinterface(c, tc->interfaces[i]))
+                               return NULL;
+
+       RT_TIMING_GET_TIME(time_fill_iftbl);
+
+       /* add finalizer method (not for java.lang.Object) */
+
+       if (super) {
+               methodinfo *fi;
+
+               fi = class_findmethod(c, utf_finalize, utf_void__void);
+
+               if (fi)
+                       if (!(fi->flags & ACC_STATIC))
+                               c->finalizer = fi;
+       }
+       RT_TIMING_GET_TIME(time_finalizer);
+
+       /* final tasks */
+
+       linker_compute_subclasses(c);
+
+       RT_TIMING_GET_TIME(time_subclasses);
+
+       /* revert the linking state and class is linked */
+
+       c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED;
+
+       /* check worklist */
+
+       /* XXX must this also be done in case of exception? */
+
+       while (worklist != NULL) {
+               method_worklist *wi = worklist;
+
+               worklist = worklist->next;
+
+               INLINELOG( printf("MUST BE RECOMPILED: "); method_println(wi->m); );
+               jit_invalidate_code(wi->m);
+
+               /* XXX put worklist into dump memory? */
+               FREE(wi, method_worklist);
+       }
+
+       RT_TIMING_TIME_DIFF(time_start        ,time_resolving    ,RT_TIMING_LINK_RESOLVE);
+       RT_TIMING_TIME_DIFF(time_resolving    ,time_compute_vftbl,RT_TIMING_LINK_C_VFTBL);
+       RT_TIMING_TIME_DIFF(time_compute_vftbl,time_abstract     ,RT_TIMING_LINK_ABSTRACT);
+       RT_TIMING_TIME_DIFF(time_abstract     ,time_compute_iftbl,RT_TIMING_LINK_C_IFTBL);
+       RT_TIMING_TIME_DIFF(time_compute_iftbl,time_fill_vftbl   ,RT_TIMING_LINK_F_VFTBL);
+       RT_TIMING_TIME_DIFF(time_fill_vftbl   ,time_offsets      ,RT_TIMING_LINK_OFFSETS);
+       RT_TIMING_TIME_DIFF(time_offsets      ,time_fill_iftbl   ,RT_TIMING_LINK_F_IFTBL);
+       RT_TIMING_TIME_DIFF(time_fill_iftbl   ,time_finalizer    ,RT_TIMING_LINK_FINALIZER);
+       RT_TIMING_TIME_DIFF(time_finalizer    ,time_subclasses   ,RT_TIMING_LINK_SUBCLASS);
+
+       /* just return c to show that we didn't had a problem */
+
+       return c;
+}
+
+
+/* link_array ******************************************************************
+
+   This function is called by link_class to create the arraydescriptor
+   for an array class.
+
+   This function returns NULL if the array cannot be linked because
+   the component type has not been linked yet.
+
+*******************************************************************************/
+
+static arraydescriptor *link_array(classinfo *c)
+{
+       classinfo       *comp;
+       s4               namelen;
+       arraydescriptor *desc;
+       vftbl_t         *compvftbl;
+       utf             *u;
+
+       comp = NULL;
+       namelen = c->name->blength;
+
+       /* Check the component type */
+
+       switch (c->name->text[1]) {
+       case '[':
+               /* c is an array of arrays. */
+               u = utf_new(c->name->text + 1, namelen - 1);
+               if (!(comp = load_class_from_classloader(u, c->classloader)))
+                       return NULL;
+               break;
+
+       case 'L':
+               /* c is an array of objects. */
+               u = utf_new(c->name->text + 2, namelen - 3);
+               if (!(comp = load_class_from_classloader(u, c->classloader)))
+                       return NULL;
+               break;
+       }
+
+       /* If the component type has not been linked, link it now */
+
+       assert(!comp || (comp->state & CLASS_LOADED));
+
+       if (comp && !(comp->state & CLASS_LINKED))
+               if (!link_class(comp))
+                       return NULL;
+
+       /* Allocate the arraydescriptor */
+
+       desc = NEW(arraydescriptor);
+
+       if (comp) {
+               /* c is an array of references */
+               desc->arraytype = ARRAYTYPE_OBJECT;
+               desc->componentsize = sizeof(void*);
+               desc->dataoffset = OFFSET(java_objectarray_t, data);
+               
+               compvftbl = comp->vftbl;
+
+               if (!compvftbl) {
+                       log_text("Component class has no vftbl");
+                       assert(0);
+               }
+
+               desc->componentvftbl = compvftbl;
+               
+               if (compvftbl->arraydesc) {
+                       desc->elementvftbl = compvftbl->arraydesc->elementvftbl;
+
+                       if (compvftbl->arraydesc->dimension >= 255) {
+                               exceptions_throw_illegalargumentexception();
+                               return NULL;
+                       }
+
+                       desc->dimension = compvftbl->arraydesc->dimension + 1;
+                       desc->elementtype = compvftbl->arraydesc->elementtype;
+
+               } else {
+                       desc->elementvftbl = compvftbl;
+                       desc->dimension = 1;
+                       desc->elementtype = ARRAYTYPE_OBJECT;
+               }
+
+       } else {
+               /* c is an array of a primitive type */
+               switch (c->name->text[1]) {
+               case 'Z':
+                       desc->arraytype = ARRAYTYPE_BOOLEAN;
+                       desc->dataoffset = OFFSET(java_booleanarray_t,data);
+                       desc->componentsize = sizeof(u1);
+                       break;
+
+               case 'B':
+                       desc->arraytype = ARRAYTYPE_BYTE;
+                       desc->dataoffset = OFFSET(java_bytearray_t,data);
+                       desc->componentsize = sizeof(u1);
+                       break;
+
+               case 'C':
+                       desc->arraytype = ARRAYTYPE_CHAR;
+                       desc->dataoffset = OFFSET(java_chararray_t,data);
+                       desc->componentsize = sizeof(u2);
+                       break;
+
+               case 'D':
+                       desc->arraytype = ARRAYTYPE_DOUBLE;
+                       desc->dataoffset = OFFSET(java_doublearray_t,data);
+                       desc->componentsize = sizeof(double);
+                       break;
+
+               case 'F':
+                       desc->arraytype = ARRAYTYPE_FLOAT;
+                       desc->dataoffset = OFFSET(java_floatarray_t,data);
+                       desc->componentsize = sizeof(float);
+                       break;
+
+               case 'I':
+                       desc->arraytype = ARRAYTYPE_INT;
+                       desc->dataoffset = OFFSET(java_intarray_t,data);
+                       desc->componentsize = sizeof(s4);
+                       break;
+
+               case 'J':
+                       desc->arraytype = ARRAYTYPE_LONG;
+                       desc->dataoffset = OFFSET(java_longarray_t,data);
+                       desc->componentsize = sizeof(s8);
+                       break;
+
+               case 'S':
+                       desc->arraytype = ARRAYTYPE_SHORT;
+                       desc->dataoffset = OFFSET(java_shortarray_t,data);
+                       desc->componentsize = sizeof(s2);
+                       break;
+
+               default:
+                       exceptions_throw_noclassdeffounderror(c->name);
+                       return NULL;
+               }
+               
+               desc->componentvftbl = NULL;
+               desc->elementvftbl = NULL;
+               desc->dimension = 1;
+               desc->elementtype = desc->arraytype;
+       }
+
+       return desc;
+}
+
+
+/* linker_compute_subclasses ***************************************************
+
+   XXX
+
+   ATTENTION: DO NOT REMOVE ANY OF THE LOCKING MECHANISMS BELOW:
+   This function needs to take the class renumber lock and stop the
+   world during class renumbering. The lock is used in C code which
+   is not that performance critical. Whereas JIT code uses critical
+   sections to atomically access the class values.
+
+*******************************************************************************/
+
+static void linker_compute_subclasses(classinfo *c)
+{
+       linker_classrenumber_mutex->lock();
+
+       if (!(c->flags & ACC_INTERFACE)) {
+               c->nextsub = NULL;
+               c->sub     = NULL;
+       }
+
+       if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) {
+               c->nextsub    = c->super->sub;
+               c->super->sub = c;
+       }
+
+       classvalue = 0;
+
+       /* compute class values */
+
+       linker_compute_class_values(class_java_lang_Object);
+
+       linker_classrenumber_mutex->unlock();
+}
+
+
+/* linker_compute_class_values *************************************************
+
+   XXX
+
+*******************************************************************************/
+
+static void linker_compute_class_values(classinfo *c)
+{
+       classinfo *subs;
+
+       c->vftbl->baseval = ++classvalue;
+
+       subs = c->sub;
+
+       while (subs) {
+               linker_compute_class_values(subs);
+
+               subs = subs->nextsub;
+       }
+
+       c->vftbl->diffval = classvalue - c->vftbl->baseval;
+}
+
+
+/* linker_addinterface *********************************************************
+
+   Is needed by link_class for adding a VTBL to a class. All
+   interfaces implemented by ic are added as well.
+
+   RETURN VALUE:
+      true.........everything ok
+         false........an exception has been thrown
+
+*******************************************************************************/
+
+static bool linker_addinterface(classinfo *c, classinfo *ic)
+{
+       s4          j, k;
+       vftbl_t    *v;
+       s4          i;
+       classinfo  *sc;
+       methodinfo *m;
+
+       v = c->vftbl;
+       i = ic->index;
+
+       if (i >= v->interfacetablelength)
+               vm_abort("Internal error: interfacetable overflow");
+
+       /* if this interface has already been added, return immediately */
+
+       if (v->interfacetable[-i] != NULL)
+               return true;
+
+       if (ic->methodscount == 0) {  /* fake entry needed for subtype test */
+               v->interfacevftbllength[i] = 1;
+               v->interfacetable[-i]      = MNEW(methodptr, 1);
+               v->interfacetable[-i][0]   = NULL;
+       }
+       else {
+               v->interfacevftbllength[i] = ic->methodscount;
+               v->interfacetable[-i]      = MNEW(methodptr, ic->methodscount);
+
+#if defined(ENABLE_STATISTICS)
+               if (opt_stat)
+                       count_vftbl_len += sizeof(methodptr) *
+                               (ic->methodscount + (ic->methodscount == 0));
+#endif
+
+               for (j = 0; j < ic->methodscount; j++) {
+                       for (sc = c; sc != NULL; sc = sc->super) {
+                               for (k = 0; k < sc->methodscount; k++) {
+                                       m = &(sc->methods[k]);
+
+                                       if (method_canoverwrite(m, &(ic->methods[j]))) {
+                                               /* method m overwrites the (abstract) method */
+#if defined(ENABLE_VERIFIER)
+                                               /* Add loading constraints (for the more
+                                                  general types of the method
+                                                  ic->methods[j]).  */
+                                               if (!classcache_add_constraints_for_params(
+                                                                       c->classloader, ic->classloader,
+                                                                       &(ic->methods[j])))
+                                               {
+                                                       return false;
+                                               }
+#endif
+
+                                               /* XXX taken from gcj */
+                                               /* check for ACC_STATIC: IncompatibleClassChangeError */
+
+                                               /* check for !ACC_PUBLIC: IllegalAccessError */
+
+                                               /* check for ACC_ABSTRACT: AbstracMethodError,
+                                                  not sure about that one */
+
+                                               v->interfacetable[-i][j] = v->table[m->vftblindex];
+                                               goto foundmethod;
+                                       }
+                               }
+                       }
+
+                       /* If no method was found, insert the AbstractMethodError
+                          stub. */
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+                       if (opt_intrp)
+                               v->interfacetable[-i][j] =
+                                       (methodptr) (ptrint) &intrp_asm_abstractmethoderror;
+                       else
+# endif
+                               v->interfacetable[-i][j] =
+                                       (methodptr) (ptrint) &asm_abstractmethoderror;
+#else
+                       v->interfacetable[-i][j] =
+                               (methodptr) (ptrint) &intrp_asm_abstractmethoderror;
+#endif
+
+               foundmethod:
+                       ;
+               }
+       }
+
+       /* add superinterfaces of this interface */
+
+       for (j = 0; j < ic->interfacescount; j++)
+               if (!linker_addinterface(c, ic->interfaces[j]))
+                       return false;
+
+       /* everything ok */
+
+       return true;
+}
+
+
+/* class_highestinterface ******************************************************
+
+   Used by the function link_class to determine the amount of memory
+   needed for the interface table.
+
+*******************************************************************************/
+
+static s4 class_highestinterface(classinfo *c)
+{
+       s4 h;
+       s4 h2;
+       s4 i;
+       
+    /* check for ACC_INTERFACE bit already done in link_class_intern */
+
+    h = c->index;
+
+       for (i = 0; i < c->interfacescount; i++) {
+               h2 = class_highestinterface(c->interfaces[i]);
+
+               if (h2 > h)
+                       h = h2;
+       }
+
+       return h;
+}
+
+#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/linker.h b/src/vm/linker.h
deleted file mode 100644 (file)
index 43dce68..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* src/vm/linker.h - class linker 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 _LINKER_H
-#define _LINKER_H
-
-/* forward typedefs ***********************************************************/
-
-typedef struct arraydescriptor arraydescriptor;
-typedef struct primitivetypeinfo primitivetypeinfo;
-
-
-#include "config.h"
-#include "vm/types.h"
-
-#include "threads/mutex.hpp"
-
-#include "vm/class.hpp"
-#include "vm/references.h"
-#include "vm/vftbl.hpp"
-
-
-/* arraydescriptor *************************************************************
-
-   For every array class an arraydescriptor is allocated which
-   describes the array class. The arraydescriptor is referenced from
-   the vftbl of the array class.
-
-*******************************************************************************/
-
-struct arraydescriptor {
-       vftbl_t *componentvftbl; /* vftbl of the component type, NULL for primit. */
-       vftbl_t *elementvftbl;   /* vftbl of the element type, NULL for primitive */
-       s2       arraytype;      /* ARRAYTYPE_* constant                          */
-       s2       dimension;      /* dimension of the array (always >= 1)          */
-       s4       dataoffset;     /* offset of the array data from object pointer  */
-       s4       componentsize;  /* size of a component in bytes                  */
-       s2       elementtype;    /* ARRAYTYPE_* constant                          */
-};
-
-
-/* global variables ***********************************************************/
-
-/* This lock must be taken while renumbering classes or while atomically      */
-/* accessing classes.                                                         */
-
-extern Mutex *linker_classrenumber_mutex;
-
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void       linker_preinit(void);
-void       linker_init(void);
-classinfo *link_class(classinfo *c);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LINKER_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/linker.hpp b/src/vm/linker.hpp
new file mode 100644 (file)
index 0000000..43dce68
--- /dev/null
@@ -0,0 +1,100 @@
+/* src/vm/linker.h - class linker 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 _LINKER_H
+#define _LINKER_H
+
+/* forward typedefs ***********************************************************/
+
+typedef struct arraydescriptor arraydescriptor;
+typedef struct primitivetypeinfo primitivetypeinfo;
+
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "threads/mutex.hpp"
+
+#include "vm/class.hpp"
+#include "vm/references.h"
+#include "vm/vftbl.hpp"
+
+
+/* arraydescriptor *************************************************************
+
+   For every array class an arraydescriptor is allocated which
+   describes the array class. The arraydescriptor is referenced from
+   the vftbl of the array class.
+
+*******************************************************************************/
+
+struct arraydescriptor {
+       vftbl_t *componentvftbl; /* vftbl of the component type, NULL for primit. */
+       vftbl_t *elementvftbl;   /* vftbl of the element type, NULL for primitive */
+       s2       arraytype;      /* ARRAYTYPE_* constant                          */
+       s2       dimension;      /* dimension of the array (always >= 1)          */
+       s4       dataoffset;     /* offset of the array data from object pointer  */
+       s4       componentsize;  /* size of a component in bytes                  */
+       s2       elementtype;    /* ARRAYTYPE_* constant                          */
+};
+
+
+/* global variables ***********************************************************/
+
+/* This lock must be taken while renumbering classes or while atomically      */
+/* accessing classes.                                                         */
+
+extern Mutex *linker_classrenumber_mutex;
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void       linker_preinit(void);
+void       linker_init(void);
+classinfo *link_class(classinfo *c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LINKER_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:
+ */
index 4f1d36fff68d90f530ec0ac276fe36fd00431f18..81ab0ad8594bd06ec0cd27cb3a0c5f6401db6209 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/linker.hpp"
 #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..b452176cb3b299760fb02518099a5b0da4159e7d 100644 (file)
@@ -37,10 +37,10 @@ typedef struct classbuffer classbuffer;
 
 #include "vm/types.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #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..59cafe9
--- /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.hpp"
+#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..6fbc0c1
--- /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.hpp"
+#include "vm/global.h"
+#include "vm/linker.hpp"
+#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 66de93d5155630e879a91ecd66cb3e81a2b945bb..052c0a370da758378dfb04365d88079499e86bb3 100644 (file)
@@ -145,6 +145,7 @@ public:
        static inline int     mprotect(void* addr, size_t len, int prot);
        static inline ssize_t readlink(const char* path, char* buf, size_t bufsiz);
        static inline int     scandir(const char* dir, struct dirent*** namelist, int(*filter)(const struct dirent*), int(*compar)(const void*, const void*));
+       static inline ssize_t send(int s, const void* buf, size_t len, int flags);
        static inline int     setsockopt(int s, int level, int optname, const void* optval, socklen_t optlen);
        static inline int     shutdown(int s, int how);
        static inline int     socket(int domain, int type, int protocol);
@@ -527,6 +528,16 @@ inline int os::scandir(const char *dir, struct dirent ***namelist, int(*filter)(
 #endif
 }
 
+inline ssize_t os::send(int s, const void* buf, size_t len, int flags)
+{
+       // TODO Should be restartable on Linux and interruptible on Solaris.
+#if defined(HAVE_SEND)
+       return ::send(s, buf, len, flags);
+#else
+# error send not available
+#endif
+}
+
 inline int os::setsockopt(int s, int level, int optname, const void* optval, socklen_t optlen)
 {
 #if defined(HAVE_SETSOCKOPT)
index 55f8cb67579372d9b332e3b27e639946ac52b4dc..314bb05d47b4d598f5c73834ba9a1981dbbad0b7 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "vm/class.hpp"
 #include "vm/global.h"
-#include "vm/linker.h"
+#include "vm/linker.hpp"
 #include "vm/utf8.h"
 
 
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 df2527fe6abca481190c456e8095bd3c3f7608d9..b10a5a7b3ad4a5631fc5d6a9988ef880d4436b8a 100644 (file)
@@ -53,6 +53,10 @@ class Properties {
 private:
        std::map<const char*, const char*, ltstr> _properties;
 
+private:
+       // Don't allow to copy the properties.
+       Properties(const Properties&);
+
 public:
        Properties();
 
index b81c2ffb56edd6a9feff279176db6e94f6d38dfc..f880b7913d42bc5855043dae63819d0d3b1ae47c 100644 (file)
@@ -62,10 +62,10 @@ typedef union parseddesc {
 #include "vm/types.h"
 
 #include "vm/class.hpp"
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/field.hpp"
 #include "vm/global.h"
-#include "vm/method.h"
+#include "vm/method.hpp"
 #include "vm/utf8.h"
 
 
index 1d1173a87d4bca833f37cb6b09aa926f02ea596f..58c7f874337ffa84546786f881595e5a1eb28f33 100644 (file)
 
 #include "mm/memory.h"
 
-#include "vm/access.h"
-#include "vm/classcache.h"
-#include "vm/descriptor.h"
+#include "vm/access.hpp"
+#include "vm/classcache.hpp"
+#include "vm/descriptor.hpp"
 #include "vm/exceptions.hpp"
 #include "vm/global.h"
 #include "vm/globals.hpp"
-#include "vm/linker.h"
+#include "vm/linker.hpp"
 #include "vm/loader.hpp"
 #include "vm/options.h"
 #include "vm/primitive.hpp"
 #include "vm/resolve.hpp"
 
 #include "vm/jit/jit.hpp"
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
 
 
 /******************************************************************************/
index 148604ebc4c9677b0f43da64ee15451ea45096e5..f75f1733813d7f5794871d966d1ab79d76559421 100644 (file)
@@ -40,14 +40,14 @@ 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"
 #include "vm/jit/reg.h"
 
 #include "vm/jit/ir/instruction.hpp"
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
 
 
 /* constants ******************************************************************/
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 c23a737cc2d2127a7c7bb73d8971659959dc5971..27926b52e5fb1f2e5f08bc42de808c80f50eceb3 100644 (file)
@@ -49,7 +49,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 522abe15eb258aec7b268e8889f55f0a8d458912..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 ***********************************************************/
@@ -238,8 +238,8 @@ void suck_add_from_property(const char *key)
        s4              namlen;
        char           *p;
 
-       /* get the property value */
-       Properties properties = VM::get_current()->get_properties();
+       // Get the property value.
+       Properties& properties = VM::get_current()->get_properties();
        value = properties.get(key);
 
        if (value == NULL)
index d05bef1af2d23e69526681cadf2f2987bb03ac0c..b5a4cc27e14ed54b9a4330ed86e12fd25f0e43a4 100644 (file)
@@ -64,9 +64,9 @@
 #endif
 
 #include "vm/jit/builtin.hpp"
-#include "vm/classcache.h"
+#include "vm/classcache.hpp"
 #include "vm/exceptions.hpp"
-#include "vm/finalizer.h"
+#include "vm/finalizer.hpp"
 #include "vm/global.h"
 #include "vm/globals.hpp"
 #include "vm/initialize.hpp"
@@ -189,6 +189,8 @@ enum {
        OPT_MS,
        OPT_MX,
 
+       OPT_XCHECK_JNI,
+
        /* CACAO options */
 
        OPT_VERBOSE1,
@@ -212,6 +214,8 @@ enum {
 
 #if defined(ENABLE_VERIFIER)
        OPT_NOVERIFY,
+       OPT_XVERIFY_ALL,
+       OPT_XVERIFY_NONE,
 #if defined(TYPECHECK_VERBOSE)
        OPT_VERBOSETC,
 #endif
@@ -304,7 +308,8 @@ opt_struct opts[] = {
        { "noasyncgc",         false, OPT_IGNORE },
 #if defined(ENABLE_VERIFIER)
        { "noverify",          false, OPT_NOVERIFY },
-       { "Xverify:none",      false, OPT_NOVERIFY },
+       { "Xverify:all",       false, OPT_XVERIFY_ALL },
+       { "Xverify:none",      false, OPT_XVERIFY_NONE },
 #endif
        { "v",                 false, OPT_VERBOSE1 },
        { "verbose:",          true,  OPT_VERBOSE },
@@ -376,6 +381,8 @@ opt_struct opts[] = {
        { "Xss",               true,  OPT_SS },
        { "ss",                true,  OPT_SS },
 
+       { "Xcheck:jni",        false, OPT_XCHECK_JNI },
+
 #if defined(ENABLE_PROFILING)
        { "Xprof:",            true,  OPT_PROF_OPTION },
        { "Xprof",             false, OPT_PROF },
@@ -976,6 +983,10 @@ VM::VM(JavaVMInitArgs* vm_args)
                        }
                        break;
 
+               case OPT_XCHECK_JNI:
+                       // HotSpot compatibility option.
+                       break;
+
                case OPT_VERBOSE1:
                        opt_verbose = true;
                        break;
@@ -1028,7 +1039,12 @@ VM::VM(JavaVMInitArgs* vm_args)
                        break;
 
 #if defined(ENABLE_VERIFIER)
+               case OPT_XVERIFY_ALL:
+                       opt_verify = true;
+                       break;
+
                case OPT_NOVERIFY:
+               case OPT_XVERIFY_NONE:
                        opt_verify = false;
                        break;
 #endif
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..09cd10a
--- /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.hpp" /* 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..d79f8ef
--- /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:
+ */
index 94e7d3d33c0fecd07b11cc7ec6d6b87605235627..0af241fdd32f0cef8e7ffe845a501f661d2325bb 100644 (file)
@@ -34,7 +34,8 @@ PR57.class,
 PR58.class,
 PR65.class,
 PR80.class,
-PR89.class
+PR89.class,
+PR112.class
 })
 
 public class All {
diff --git a/tests/regression/bugzilla/PR112.java b/tests/regression/bugzilla/PR112.java
new file mode 100644 (file)
index 0000000..7611ddd
--- /dev/null
@@ -0,0 +1,44 @@
+/* tests/regression/bugzilla/PR112.java
+
+   Copyright (C) 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.
+
+*/
+
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+import java.lang.reflect.*;
+
+public class PR112 {
+    @Test ( expected = IllegalArgumentException.class )
+    public void test() throws IllegalArgumentException {
+        // Derived from OpenJDK's jdk jtreg test
+        // java/lang/reflect/Array/ExceedMaxDim.java
+        Object o = Array.newInstance(Integer.TYPE, 0);
+
+        for (int i = 1; i <= 254; i++) {
+            o = Array.newInstance(o.getClass(), 1);
+        }
+
+        o = Array.newInstance(o.getClass(), 1);
+    }
+}