Logo Search packages:      
Sourcecode: cacao-source version File versions  Download package

vm.c

/* src/vm/vm.c - VM startup and shutdown 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 <errno.h>
#include <stdint.h>
#include <stdlib.h>

#include "vm/types.h"

#include "arch.h"
#include "md-abi.h"

#include "vm/jit/abi-asm.h"

#include "mm/codememory.h"
#include "mm/gc-common.h"
#include "mm/memory.h"

#include "native/jni.h"
#include "native/llni.h"
#include "native/localref.h"
#include "native/native.h"

#include "native/include/java_lang_Object.h"             /* required by j.l.C */
#include "native/include/java_lang_String.h"             /* required by j.l.C */

#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
# include "native/include/java_nio_ByteBuffer.h"        /* required by j.l.CL */
# include "native/include/java_lang_ClassLoader.h"       /* required by j.l.C */
#endif

#include "native/include/java_lang_Class.h"

#include "native/vm/nativevm.h"

#include "threads/lock-common.h"
#include "threads/mutex.h"
#include "threads/threadlist.h"
#include "threads/thread.h"

#include "toolbox/logging.h"

#include "vm/array.h"

#if defined(ENABLE_ASSERTION)
#include "vm/assertion.h"
#endif

#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vm/finalizer.h"
#include "vm/global.h"
#include "vm/initialize.h"
#include "vm/package.h"
#include "vm/primitive.h"
#include "vm/properties.h"
#include "vm/signallocal.h"
#include "vm/stringlocal.h"
#include "vm/vm.h"

#include "vm/jit/argument.h"
#include "vm/jit/asmpart.h"
#include "vm/jit/code.h"

#if defined(ENABLE_DISASSEMBLER)
# include "vm/jit/disass.h"
#endif

#include "vm/jit/jit.h"
#include "vm/jit/methodtree.h"

#if defined(ENABLE_PROFILING)
# include "vm/jit/optimizing/profile.h"
#endif

#include "vm/jit/optimizing/recompile.h"

#if defined(ENABLE_PYTHON)
# include "vm/jit/python.h"
#endif

#include "vm/jit/trap.h"

#include "vmcore/classcache.h"
#include "vmcore/options.h"
#include "vmcore/statistics.h"
#include "vmcore/suck.h"
#include "vmcore/system.h"

#if defined(ENABLE_JVMTI)
# include "native/jvmti/cacaodbg.h"
#endif

#if defined(ENABLE_VMLOG)
#include <vmlog_cacao.h>
#endif


/* Invocation API variables ***************************************************/

_Jv_JavaVM *_Jv_jvm;                    /* denotes a Java VM                  */
_Jv_JNIEnv *_Jv_env;                    /* pointer to native method interface */


/* global variables ***********************************************************/

s4 vms = 0;                             /* number of VMs created              */

bool vm_initializing = false;
bool vm_created      = false;
bool vm_exiting      = false;

static classinfo *mainclass = NULL;

#if defined(ENABLE_INTRP)
u1 *intrp_main_stack = NULL;
#endif


/* define heap sizes **********************************************************/

#define HEAP_MAXSIZE      128 * 1024 * 1024 /* default 128MB                  */
#define HEAP_STARTSIZE      2 * 1024 * 1024 /* default 2MB                    */
#define STACK_SIZE               128 * 1024 /* default 64kB                   */


/* define command line options ************************************************/

enum {
      OPT_FOO,

      /* Java options */

      OPT_JAR,

      OPT_D32,
      OPT_D64,

      OPT_CLASSPATH,
      OPT_D,

      OPT_VERBOSE,

      OPT_VERSION,
      OPT_SHOWVERSION,
      OPT_FULLVERSION,

      OPT_HELP,
      OPT_X,
      OPT_XX,

      OPT_EA,
      OPT_DA,
      OPT_EA_NOARG,
      OPT_DA_NOARG,
    

      OPT_ESA,
      OPT_DSA,

      /* Java non-standard options */

      OPT_JIT,
      OPT_INTRP,

      OPT_BOOTCLASSPATH,
      OPT_BOOTCLASSPATH_A,
      OPT_BOOTCLASSPATH_P,

      OPT_BOOTCLASSPATH_C,

#if defined(ENABLE_PROFILING)
      OPT_PROF,
      OPT_PROF_OPTION,
#endif

      OPT_MS,
      OPT_MX,

      OPT_XCHECK_JNI,

      /* CACAO options */

      OPT_VERBOSE1,
      OPT_NOIEEE,

#if defined(ENABLE_STATISTICS)
      OPT_TIME,
      OPT_STAT,
#endif

      OPT_LOG,
      OPT_CHECK,
      OPT_LOAD,
      OPT_SHOW,
      OPT_DEBUGCOLOR,

#if !defined(NDEBUG)
      OPT_ALL,
      OPT_METHOD,
      OPT_SIGNATURE,
#endif

#if defined(ENABLE_VERIFIER)
      OPT_NOVERIFY,
      OPT_XVERIFY_ALL,
      OPT_XVERIFY_NONE,
#if defined(TYPECHECK_VERBOSE)
      OPT_VERBOSETC,
#endif
#endif /* defined(ENABLE_VERIFIER) */

      /* optimization options */

#if defined(ENABLE_LOOP)
      OPT_OLOOP,
#endif
      
#if defined(ENABLE_IFCONV)
      OPT_IFCONV,
#endif

#if defined(ENABLE_LSRA) || defined(ENABLE_SSA)
      OPT_LSRA,
#endif

#if defined(ENABLE_INTRP)
      /* interpreter options */

      OPT_NO_DYNAMIC,
      OPT_NO_REPLICATION,
      OPT_NO_QUICKSUPER,
      OPT_STATIC_SUPERS,
      OPT_TRACE,
#endif

      OPT_SS,

#ifdef ENABLE_JVMTI
      OPT_DEBUG,
      OPT_XRUNJDWP,
      OPT_NOAGENT,
      OPT_AGENTLIB,
      OPT_AGENTPATH,
#endif

#if defined(ENABLE_DEBUG_FILTER)
      OPT_FILTER_VERBOSECALL_INCLUDE,
      OPT_FILTER_VERBOSECALL_EXCLUDE,
      OPT_FILTER_SHOW_METHOD,
#endif

      DUMMY
};


opt_struct opts[] = {
      { "foo",               false, OPT_FOO },

      /* Java options */

      { "jar",               false, OPT_JAR },

      { "d32",               false, OPT_D32 },
      { "d64",               false, OPT_D64 },
      { "client",            false, OPT_IGNORE },
      { "server",            false, OPT_IGNORE },
      { "jvm",               false, OPT_IGNORE },
      { "hotspot",           false, OPT_IGNORE },

      { "classpath",         true,  OPT_CLASSPATH },
      { "cp",                true,  OPT_CLASSPATH },
      { "D",                 true,  OPT_D },
      { "version",           false, OPT_VERSION },
      { "showversion",       false, OPT_SHOWVERSION },
      { "fullversion",       false, OPT_FULLVERSION },
      { "help",              false, OPT_HELP },
      { "?",                 false, OPT_HELP },
      { "X",                 false, OPT_X },
      { "XX:",               true,  OPT_XX },

      { "ea:",               true,  OPT_EA },
      { "da:",               true,  OPT_DA },
      { "ea",                false, OPT_EA_NOARG },
      { "da",                false, OPT_DA_NOARG },

      { "enableassertions:",  true,  OPT_EA },
      { "disableassertions:", true,  OPT_DA },
      { "enableassertions",   false, OPT_EA_NOARG },
      { "disableassertions",  false, OPT_DA_NOARG },

      { "esa",                     false, OPT_ESA },
      { "enablesystemassertions",  false, OPT_ESA },
      { "dsa",                     false, OPT_DSA },
      { "disablesystemassertions", false, OPT_DSA },

      { "noasyncgc",         false, OPT_IGNORE },
#if defined(ENABLE_VERIFIER)
      { "noverify",          false, OPT_NOVERIFY },
      { "Xverify:all",       false, OPT_XVERIFY_ALL },
      { "Xverify:none",      false, OPT_XVERIFY_NONE },
#endif
      { "v",                 false, OPT_VERBOSE1 },
      { "verbose:",          true,  OPT_VERBOSE },

#if defined(ENABLE_VERIFIER) && defined(TYPECHECK_VERBOSE)
      { "verbosetc",         false, OPT_VERBOSETC },
#endif
#if defined(__ALPHA__)
      { "noieee",            false, OPT_NOIEEE },
#endif
#if defined(ENABLE_STATISTICS)
      { "time",              false, OPT_TIME },
      { "stat",              false, OPT_STAT },
#endif
      { "log",               true,  OPT_LOG },
      { "c",                 true,  OPT_CHECK },
      { "l",                 false, OPT_LOAD },

#if !defined(NDEBUG)
      { "all",               false, OPT_ALL },
      { "sig",               true,  OPT_SIGNATURE },
#endif

#if defined(ENABLE_LOOP)
      { "oloop",             false, OPT_OLOOP },
#endif
#if defined(ENABLE_IFCONV)
      { "ifconv",            false, OPT_IFCONV },
#endif
#if defined(ENABLE_LSRA)
      { "lsra",              false, OPT_LSRA },
#endif
#if  defined(ENABLE_SSA)
      { "lsra",              true, OPT_LSRA },
#endif

#if defined(ENABLE_INTRP)
      /* interpreter options */

      { "trace",             false, OPT_TRACE },
      { "static-supers",     true,  OPT_STATIC_SUPERS },
      { "no-dynamic",        false, OPT_NO_DYNAMIC },
      { "no-replication",    false, OPT_NO_REPLICATION },
      { "no-quicksuper",     false, OPT_NO_QUICKSUPER },
#endif

      /* JVMTI Agent Command Line Options */
#ifdef ENABLE_JVMTI
      { "agentlib:",         true,  OPT_AGENTLIB },
      { "agentpath:",        true,  OPT_AGENTPATH },
#endif

      /* Java non-standard options */

      { "Xjit",              false, OPT_JIT },
      { "Xint",              false, OPT_INTRP },
      { "Xbootclasspath:",   true,  OPT_BOOTCLASSPATH },
      { "Xbootclasspath/a:", true,  OPT_BOOTCLASSPATH_A },
      { "Xbootclasspath/p:", true,  OPT_BOOTCLASSPATH_P },
      { "Xbootclasspath/c:", true,  OPT_BOOTCLASSPATH_C },

#ifdef ENABLE_JVMTI
      { "Xdebug",            false, OPT_DEBUG },
      { "Xnoagent",          false, OPT_NOAGENT },
      { "Xrunjdwp",          true,  OPT_XRUNJDWP },
#endif 

      { "Xms",               true,  OPT_MS },
      { "ms",                true,  OPT_MS },
      { "Xmx",               true,  OPT_MX },
      { "mx",                true,  OPT_MX },
      { "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 },
#endif

      /* keep these at the end of the list */

#if !defined(NDEBUG)
      { "m",                 true,  OPT_METHOD },
#endif

      { "s",                 true,  OPT_SHOW },
      { "debug-color",      false,  OPT_DEBUGCOLOR },

#if defined(ENABLE_DEBUG_FILTER)
      { "XXfi",              true,  OPT_FILTER_VERBOSECALL_INCLUDE },
      { "XXfx",              true,  OPT_FILTER_VERBOSECALL_EXCLUDE },
      { "XXfm",              true,  OPT_FILTER_SHOW_METHOD },
#endif

      { NULL,                false, 0 }
};


/* usage ***********************************************************************

   Prints the correct usage syntax to stdout.

*******************************************************************************/

void usage(void)
{
      puts("Usage: cacao [-options] classname [arguments]");
      puts("               (to run a class file)");
      puts("   or  cacao [-options] -jar jarfile [arguments]");
      puts("               (to run a standalone jar file)\n");

      puts("where options include:");
      puts("    -d32                     use 32-bit data model if available");
      puts("    -d64                     use 64-bit data model if available");
      puts("    -client                  compatibility (currently ignored)");
      puts("    -server                  compatibility (currently ignored)");
      puts("    -jvm                     compatibility (currently ignored)");
      puts("    -hotspot                 compatibility (currently ignored)\n");

      puts("    -cp <path>               specify a path to look for classes");
      puts("    -classpath <path>        specify a path to look for classes");
      puts("    -D<name>=<value>         add an entry to the property list");
      puts("    -verbose[:class|gc|jni]  enable specific verbose output");
      puts("    -version                 print product version and exit");
      puts("    -fullversion             print jpackage-compatible product version and exit");
      puts("    -showversion             print product version and continue");
      puts("    -help, -?                print this help message");
      puts("    -X                       print help on non-standard Java options");
      puts("    -XX                      print help on debugging options");
    puts("    -ea[:<packagename>...|:<classname>]");
    puts("    -enableassertions[:<packagename>...|:<classname>]");
      puts("                             enable assertions with specified granularity");
      puts("    -da[:<packagename>...|:<classname>]");
      puts("    -disableassertions[:<packagename>...|:<classname>]");
      puts("                             disable assertions with specified granularity");
      puts("    -esa | -enablesystemassertions");
      puts("                             enable system assertions");
      puts("    -dsa | -disablesystemassertions");
      puts("                             disable system assertions");

#ifdef ENABLE_JVMTI
      puts("    -agentlib:<agent-lib-name>=<options>  library to load containg JVMTI agent");
      puts ("                                         for jdwp help use: -agentlib:jdwp=help");
      puts("    -agentpath:<path-to-agent>=<options>  path to library containg JVMTI agent");
#endif

      /* exit with error code */

      exit(1);
}   


static void Xusage(void)
{
#if defined(ENABLE_JIT)
      puts("    -Xjit                    JIT mode execution (default)");
#endif
#if defined(ENABLE_INTRP)
      puts("    -Xint                    interpreter mode execution");
#endif
      puts("    -Xbootclasspath:<zip/jar files and directories separated by :>");
    puts("                             value is set as bootstrap class path");
      puts("    -Xbootclasspath/a:<zip/jar files and directories separated by :>");
      puts("                             value is appended to the bootstrap class path");
      puts("    -Xbootclasspath/p:<zip/jar files and directories separated by :>");
      puts("                             value is prepended to the bootstrap class path");
      puts("    -Xbootclasspath/c:<zip/jar files and directories separated by :>");
      puts("                             value is used as Java core library, but the");
      puts("                             hardcoded VM interface classes are prepended");
      printf("    -Xms<size>               set the initial size of the heap (default: %dMB)\n", HEAP_STARTSIZE / 1024 / 1024);
      printf("    -Xmx<size>               set the maximum size of the heap (default: %dMB)\n", HEAP_MAXSIZE / 1024 / 1024);
      printf("    -Xss<size>               set the thread stack size (default: %dkB)\n", STACK_SIZE / 1024);

#if defined(ENABLE_PROFILING)
      puts("    -Xprof[:bb]              collect and print profiling data");
#endif

#if defined(ENABLE_JVMTI)
    /* -Xdebug option depend on gnu classpath JDWP options. options: 
       transport=dt_socket,address=<hostname:port>,server=(y|n),suspend(y|n) */
      puts("    -Xdebug                  enable remote debugging\n");
      puts("    -Xrunjdwp transport=[dt_socket|...],address=<hostname:port>,server=[y|n],suspend=[y|n]\n");
      puts("                             enable remote debugging\n");
#endif 

      /* exit with error code */

      exit(1);
}   


#if 0
static void XXusage(void)
{
      puts("    -v                       write state-information");
#if !defined(NDEBUG)
      puts("    -verbose:jit             enable specific verbose output");
      puts("    -debug-color             colored output for ANSI terms");
#endif
#ifdef TYPECHECK_VERBOSE
      puts("    -verbosetc               write debug messages while typechecking");
#endif
#if defined(__ALPHA__)
      puts("    -noieee                  don't use ieee compliant arithmetic");
#endif
#if defined(ENABLE_VERIFIER)
      puts("    -noverify                don't verify classfiles");
#endif
#if defined(ENABLE_STATISTICS)
      puts("    -time                    measure the runtime");
      puts("    -stat                    detailed compiler statistics");
#endif
      puts("    -log logfile             specify a name for the logfile");
      puts("    -c(heck)b(ounds)         don't check array bounds");
      puts("            s(ync)           don't check for synchronization");
#if defined(ENABLE_LOOP)
      puts("    -oloop                   optimize array accesses in loops");
#endif
      puts("    -l                       don't start the class after loading");
#if !defined(NDEBUG)
      puts("    -all                     compile all methods, no execution");
      puts("    -m                       compile only a specific method");
      puts("    -sig                     specify signature for a specific method");
#endif

      puts("    -s...                    show...");
      puts("      (c)onstants            the constant pool");
      puts("      (m)ethods              class fields and methods");
      puts("      (u)tf                  the utf - hash");
      puts("      (i)ntermediate         intermediate representation");
#if defined(ENABLE_DISASSEMBLER)
      puts("      (a)ssembler            disassembled listing");
      puts("      n(o)ps                 show NOPs in disassembler output");
#endif
      puts("      (d)atasegment          data segment listing");

#if defined(ENABLE_IFCONV)
      puts("    -ifconv                  use if-conversion");
#endif
#if defined(ENABLE_LSRA)
      puts("    -lsra                    use linear scan register allocation");
#endif
#if defined(ENABLE_SSA)
      puts("    -lsra:...                use linear scan register allocation (with SSA)");
      puts("       (d)ead code elimination");
      puts("       (c)opy propagation");
#endif
#if defined(ENABLE_DEBUG_FILTER)
      puts("    -XXfi <regex>            begin of dynamic scope for verbosecall filter");
      puts("    -XXfx <regex>            end of dynamic scope for verbosecall filter");
      puts("    -XXfm <regex>            filter for show options");
#endif
      /* exit with error code */

      exit(1);
}
#endif


/* version *********************************************************************

   Only prints cacao version information.

*******************************************************************************/

static void version(bool opt_exit)
{
      puts("java version \""JAVA_VERSION"\"");
      puts("CACAO version "VERSION"\n");

      puts("Copyright (C) 1996-2005, 2006, 2007, 2008");
      puts("CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO");
      puts("This is free software; see the source for copying conditions.  There is NO");
      puts("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");

      /* exit normally, if requested */

      if (opt_exit)
            exit(0);
}


/* fullversion *****************************************************************

   Prints a Sun compatible version information (required e.g. by
   jpackage, www.jpackage.org).

*******************************************************************************/

static void fullversion(void)
{
      puts("java full version \"cacao-"JAVA_VERSION"\"");

      /* exit normally */

      exit(0);
}


static void vm_printconfig(void)
{
      puts("Configure/Build options:\n");
      puts("  ./configure: "VERSION_CONFIGURE_ARGS"");
#if defined(__VERSION__)
      puts("  CC         : "VERSION_CC" ("__VERSION__")");
#else
      puts("  CC         : "VERSION_CC"");
#endif
      puts("  CFLAGS     : "VERSION_CFLAGS"\n");

      puts("Default variables:\n");
      printf("  maximum heap size              : %d\n", HEAP_MAXSIZE);
      printf("  initial heap size              : %d\n", HEAP_STARTSIZE);
      printf("  stack size                     : %d\n", STACK_SIZE);

#if defined(ENABLE_JRE_LAYOUT)
      /* When we're building with JRE-layout, the default paths are the
         same as the runtime paths. */
#else
# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
      puts("  gnu.classpath.boot.library.path: "JAVA_RUNTIME_LIBRARY_LIBDIR);
      puts("  java.boot.class.path           : "CACAO_VM_ZIP":"JAVA_RUNTIME_LIBRARY_CLASSES"");
# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
      puts("  sun.boot.library.path          : "JAVA_RUNTIME_LIBRARY_LIBDIR);
      puts("  java.boot.class.path           : "JAVA_RUNTIME_LIBRARY_CLASSES);
# endif
#endif

      puts("");

      puts("Runtime variables:\n");
      printf("  maximum heap size              : %d\n", opt_heapmaxsize);
      printf("  initial heap size              : %d\n", opt_heapstartsize);
      printf("  stack size                     : %d\n", opt_stacksize);

#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
      printf("  gnu.classpath.boot.library.path: %s\n", properties_get("gnu.classpath.boot.library.path"));
#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
      printf("  sun.boot.library.path          : %s\n", properties_get("sun.boot.library.path"));
#endif

      printf("  java.boot.class.path           : %s\n", properties_get("java.boot.class.path"));
      printf("  java.class.path                : %s\n", properties_get("java.class.path"));
}


/* forward declarations *******************************************************/

static char *vm_get_mainclass_from_jar(char *mainstring);
#if !defined(NDEBUG)
static void  vm_compile_all(void);
static void  vm_compile_method(char* mainname);
#endif


/* vm_createjvm ****************************************************************

   Implementation for JNI_CreateJavaVM.

*******************************************************************************/

bool vm_createjvm(JavaVM **p_vm, void **p_env, void *vm_args)
{
      JavaVMInitArgs *_vm_args;
      _Jv_JNIEnv     *env;
      _Jv_JavaVM     *vm;

      /* get the arguments for the new JVM */

      _vm_args = (JavaVMInitArgs *) vm_args;

      /* get the VM and Env tables (must be set before vm_create) */

      env = NEW(_Jv_JNIEnv);

#if defined(ENABLE_JNI)
      env->env = &_Jv_JNINativeInterface;
#endif

      /* XXX Set the global variable.  Maybe we should do that differently. */

      _Jv_env = env;

      /* create and fill a JavaVM structure */

      vm = NEW(_Jv_JavaVM);

#if defined(ENABLE_JNI)
      vm->functions = &_Jv_JNIInvokeInterface;
#endif

      /* XXX Set the global variable.  Maybe we should do that differently. */
      /* XXX JVMTI Agents needs a JavaVM  */

      _Jv_jvm = vm;

      /* actually create the JVM */

      if (!vm_create(_vm_args))
            goto error;

      /* now return the values */

      *p_vm  = (JavaVM *) vm;
      *p_env = (void *) env;

      return true;

 error:
      /* release allocated memory */

      FREE(env, _Jv_JNIEnv);
      FREE(vm, _Jv_JavaVM);

      return false;
}


/* vm_create *******************************************************************

   Creates a JVM.  Called by vm_createjvm.

*******************************************************************************/

bool vm_create(JavaVMInitArgs *vm_args)
{
      int   len;
      char *p;
      char *boot_class_path;
      char *class_path;
      int   opt;
      int   i, j;
      bool  opt_version;
      bool  opt_exit;

#if defined(ENABLE_JVMTI)
      lt_dlhandle  handle;
      char *libname, *agentarg;
      bool jdwp,agentbypath;
      jdwp = agentbypath = false;
#endif

#if defined(ENABLE_JNI)
      /* Check the JNI version requested. */

      if (!jni_version_check(vm_args->version))
            return false;
#endif

      /* We only support 1 JVM instance. */

      if (vms > 0)
            return false;

      /* Install the exit handler. */

      if (atexit(vm_exit_handler))
            vm_abort("atexit failed: %s\n", strerror(errno));

      /* Set some options. */

      opt_version       = false;
      opt_exit          = false;

      opt_noieee        = false;

      opt_heapmaxsize   = HEAP_MAXSIZE;
      opt_heapstartsize = HEAP_STARTSIZE;
      opt_stacksize     = STACK_SIZE;

      /* Initialize the properties list before command-line handling.
         Otherwise -XX:+PrintConfig crashes. */

      properties_init();

      /* First of all, parse the -XX options. */

#if defined(ENABLE_VMLOG)
      vmlog_cacao_init_options();
#endif

      options_xx(vm_args);

#if defined(ENABLE_VMLOG)
      vmlog_cacao_init();
#endif

      /* We need to check if the actual size of a java.lang.Class object
         is smaller or equal than the assumption made in
         src/vmcore/class.h. */

      if (sizeof(java_lang_Class) > sizeof(dummy_java_lang_Class))
            vm_abort("vm_create: java_lang_Class structure is bigger than classinfo.object (%d > %d)", sizeof(java_lang_Class), sizeof(dummy_java_lang_Class));

      /* set the VM starttime */

      _Jv_jvm->starttime = builtin_currenttimemillis();

#if defined(ENABLE_JVMTI)
      /* initialize JVMTI related  **********************************************/
      jvmti = false;
#endif

      /* Fill the properties before command-line handling. */

      properties_set();

      /* iterate over all passed options */

      while ((opt = options_get(opts, vm_args)) != OPT_DONE) {
            switch (opt) {
            case OPT_FOO:
                  opt_foo = true;
                  break;

            case OPT_IGNORE:
                  break;
                  
            case OPT_JAR:
                  opt_jar = true;
                  break;

            case OPT_D32:
#if SIZEOF_VOID_P == 8
                  puts("Running a 32-bit JVM is not supported on this platform.");
                  exit(1);
#endif
                  break;

            case OPT_D64:
#if SIZEOF_VOID_P == 4
                  puts("Running a 64-bit JVM is not supported on this platform.");
                  exit(1);
#endif
                  break;

            case OPT_CLASSPATH:
                  /* Forget old classpath and set the argument as new
                     classpath. */

                  class_path = properties_get("java.class.path");

                  p = MNEW(char, strlen(opt_arg) + strlen("0"));

                  strcpy(p, opt_arg);

#if defined(ENABLE_JAVASE)
                  properties_add("java.class.path", p);
#endif

                  MFREE(class_path, char, strlen(class_path));
                  break;

            case OPT_D:
                  for (i = 0; i < strlen(opt_arg); i++) {
                        if (opt_arg[i] == '=') {
                              opt_arg[i] = '\0';
                              properties_add(opt_arg, opt_arg + i + 1);
                              goto opt_d_done;
                        }
                  }

                  /* if no '=' is given, just create an empty property */

                  properties_add(opt_arg, "");

            opt_d_done:
                  break;

            case OPT_BOOTCLASSPATH:
                  /* Forget default bootclasspath and set the argument as
                     new boot classpath. */

                  boot_class_path = properties_get("sun.boot.class.path");

                  p = MNEW(char, strlen(opt_arg) + strlen("0"));

                  strcpy(p, opt_arg);

                  properties_add("sun.boot.class.path", p);
                  properties_add("java.boot.class.path", p);

                  MFREE(boot_class_path, char, strlen(boot_class_path));
                  break;

            case OPT_BOOTCLASSPATH_A:
                  /* Append to bootclasspath. */

                  boot_class_path = properties_get("sun.boot.class.path");

                  len = strlen(boot_class_path);

                  p = MREALLOC(boot_class_path,
                                     char,
                                     len + strlen("0"),
                                     len + strlen(":") +
                                     strlen(opt_arg) + strlen("0"));

                  strcat(p, ":");
                  strcat(p, opt_arg);

                  properties_add("sun.boot.class.path", p);
                  properties_add("java.boot.class.path", p);
                  break;

            case OPT_BOOTCLASSPATH_P:
                  /* Prepend to bootclasspath. */

                  boot_class_path = properties_get("sun.boot.class.path");

                  len = strlen(boot_class_path);

                  p = MNEW(char, strlen(opt_arg) + strlen(":") + len + strlen("0"));

                  strcpy(p, opt_arg);
                  strcat(p, ":");
                  strcat(p, boot_class_path);

                  properties_add("sun.boot.class.path", p);
                  properties_add("java.boot.class.path", p);

                  MFREE(boot_class_path, char, len);
                  break;

            case OPT_BOOTCLASSPATH_C:
                  /* Use as Java core library, but prepend VM interface
                     classes. */

                  boot_class_path = properties_get("sun.boot.class.path");

                  len =
                        strlen(CACAO_VM_ZIP) +
                        strlen(":") +
                        strlen(opt_arg) +
                        strlen("0");

                  p = MNEW(char, len);

                  strcpy(p, CACAO_VM_ZIP);
                  strcat(p, ":");
                  strcat(p, opt_arg);

                  properties_add("sun.boot.class.path", p);
                  properties_add("java.boot.class.path", p);

                  MFREE(boot_class_path, char, strlen(boot_class_path));
                  break;

#if defined(ENABLE_JVMTI)
            case OPT_DEBUG:
                  /* this option exists only for compatibility reasons */
                  break;

            case OPT_NOAGENT:
                  /* I don't know yet what Xnoagent should do. This is only for 
                     compatiblity with eclipse - motse */
                  break;

            case OPT_XRUNJDWP:
                  agentbypath = true;
                  jvmti       = true;
                  jdwp        = true;

                  len =
                        strlen(CACAO_LIBDIR) +
                        strlen("/libjdwp.so=") +
                        strlen(opt_arg) +
                        strlen("0");

                  agentarg = MNEW(char, len);

                  strcpy(agentarg, CACAO_LIBDIR);
                  strcat(agentarg, "/libjdwp.so=");
                  strcat(agentarg, &opt_arg[1]);
                  break;

            case OPT_AGENTPATH:
                  agentbypath = true;

            case OPT_AGENTLIB:
                  jvmti = true;
                  agentarg = opt_arg;
                  break;
#endif
                  
            case OPT_MX:
            case OPT_MS:
            case OPT_SS:
                  {
                        char c;
                        c = opt_arg[strlen(opt_arg) - 1];

                        if ((c == 'k') || (c == 'K')) {
                              j = atoi(opt_arg) * 1024;

                        } else if ((c == 'm') || (c == 'M')) {
                              j = atoi(opt_arg) * 1024 * 1024;

                        } else
                              j = atoi(opt_arg);

                        if (opt == OPT_MX)
                              opt_heapmaxsize = j;
                        else if (opt == OPT_MS)
                              opt_heapstartsize = j;
                        else
                              opt_stacksize = j;
                  }
                  break;

            case OPT_XCHECK_JNI:
                  // HotSpot compatibility option.
                  break;

            case OPT_VERBOSE1:
                  opt_verbose = true;
                  break;

            case OPT_VERBOSE:
                  if (strcmp("class", opt_arg) == 0) {
                        opt_verboseclass = true;
                  }
                  else if (strcmp("gc", opt_arg) == 0) {
                        opt_verbosegc = true;
                  }
                  else if (strcmp("jni", opt_arg) == 0) {
                        opt_verbosejni = true;
                  }
#if !defined(NDEBUG)
                  else if (strcmp("jit", opt_arg) == 0) {
                        opt_verbose = true;
                        loadverbose = true;
                        initverbose = true;
                        compileverbose = true;
                  }
#endif
                  else {
                        printf("Unknown -verbose option: %s\n", opt_arg);
                        usage();
                  }
                  break;

            case OPT_DEBUGCOLOR:
                  opt_debugcolor = true;
                  break;

#if defined(ENABLE_VERIFIER) && defined(TYPECHECK_VERBOSE)
            case OPT_VERBOSETC:
                  opt_typecheckverbose = true;
                  break;
#endif
                        
            case OPT_VERSION:
                  opt_version = true;
                  opt_exit    = true;
                  break;

            case OPT_FULLVERSION:
                  fullversion();
                  break;

            case OPT_SHOWVERSION:
                  opt_version = true;
                  break;

            case OPT_NOIEEE:
                  opt_noieee = true;
                  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

#if defined(ENABLE_STATISTICS)
            case OPT_TIME:
                  opt_getcompilingtime = true;
                  opt_getloadingtime = true;
                  break;
                              
            case OPT_STAT:
                  opt_stat = true;
                  break;
#endif
                              
            case OPT_LOG:
                  log_init(opt_arg);
                  break;
                  
            case OPT_CHECK:
                  for (i = 0; i < strlen(opt_arg); i++) {
                        switch (opt_arg[i]) {
                        case 'b':
                              checkbounds = false;
                              break;
                        case 's':
                              checksync = false;
                              break;
                        default:
                              usage();
                        }
                  }
                  break;
                  
            case OPT_LOAD:
                  opt_run = false;
                  makeinitializations = false;
                  break;

#if !defined(NDEBUG)
            case OPT_ALL:
                  compileall = true;
                  opt_run = false;
                  makeinitializations = false;
                  break;

            case OPT_METHOD:
                  opt_run = false;
                  opt_method = opt_arg;
                  makeinitializations = false;
                  break;

            case OPT_SIGNATURE:
                  opt_signature = opt_arg;
                  break;
#endif

            case OPT_SHOW:       /* Display options */
                  for (i = 0; i < strlen(opt_arg); i++) {         
                        switch (opt_arg[i]) {
                        case 'c':
                              showconstantpool = true;
                              break;

                        case 'u':
                              showutf = true;
                              break;

                        case 'm':
                              showmethods = true;
                              break;

                        case 'i':
                              opt_showintermediate = true;
                              compileverbose = true;
                              break;

#if defined(ENABLE_DISASSEMBLER)
                        case 'a':
                              opt_showdisassemble = true;
                              compileverbose = true;
                              break;
#endif

                        case 'd':
                              opt_showddatasegment = true;
                              break;

                        default:
                              usage();
                        }
                  }
                  break;
                  
#if defined(ENABLE_LOOP)
            case OPT_OLOOP:
                  opt_loops = true;
                  break;
#endif

#if defined(ENABLE_IFCONV)
            case OPT_IFCONV:
                  opt_ifconv = true;
                  break;
#endif

#if defined(ENABLE_LSRA)
            case OPT_LSRA:
                  opt_lsra = true;
                  break;
#endif
#if  defined(ENABLE_SSA)
            case OPT_LSRA:
                  opt_lsra = true;
                  for (i = 0; i < strlen(opt_arg); i++) {         
                        switch (opt_arg[i]) {
                        case 'c':
                              opt_ssa_cp = true;
                              break;

                        case 'd':
                              opt_ssa_dce = true;
                              break;

                        case ':':
                              break;

                        default:
                              usage();
                        }
                  }
                  break;
#endif

            case OPT_HELP:
                  usage();
                  break;

            case OPT_X:
                  Xusage();
                  break;

            case OPT_XX:
                  /* Already parsed. */
                  break;

            case OPT_EA:
#if defined(ENABLE_ASSERTION)
                  assertion_ea_da(opt_arg, true);
#endif
                  break;

            case OPT_DA:
#if defined(ENABLE_ASSERTION)
                  assertion_ea_da(opt_arg, false);
#endif
                  break;

            case OPT_EA_NOARG:
#if defined(ENABLE_ASSERTION)
                  assertion_user_enabled = true;
#endif
                  break;

            case OPT_DA_NOARG:
#if defined(ENABLE_ASSERTION)
                  assertion_user_enabled = false;
#endif
                  break;

            case OPT_ESA:
#if defined(ENABLE_ASSERTION)
                  assertion_system_enabled = true;
#endif
                  break;

            case OPT_DSA:
#if defined(ENABLE_ASSERTION)
                  assertion_system_enabled = false;
#endif
                  break;

#if defined(ENABLE_PROFILING)
            case OPT_PROF_OPTION:
                  /* use <= to get the last \0 too */

                  for (i = 0, j = 0; i <= strlen(opt_arg); i++) {
                        if (opt_arg[i] == ',')
                              opt_arg[i] = '\0';

                        if (opt_arg[i] == '\0') {
                              if (strcmp("bb", opt_arg + j) == 0)
                                    opt_prof_bb = true;

                              else {
                                    printf("Unknown option: -Xprof:%s\n", opt_arg + j);
                                    usage();
                              }

                              /* set k to next char */

                              j = i + 1;
                        }
                  }
                  /* fall through */

            case OPT_PROF:
                  opt_prof = true;
                  break;
#endif

            case OPT_JIT:
#if defined(ENABLE_JIT)
                  opt_jit = true;
#else
                  printf("-Xjit option not enabled.\n");
                  exit(1);
#endif
                  break;

            case OPT_INTRP:
#if defined(ENABLE_INTRP)
                  opt_intrp = true;
#else
                  printf("-Xint option not enabled.\n");
                  exit(1);
#endif
                  break;

#if defined(ENABLE_INTRP)
            case OPT_STATIC_SUPERS:
                  opt_static_supers = atoi(opt_arg);
                  break;

            case OPT_NO_DYNAMIC:
                  opt_no_dynamic = true;
                  break;

            case OPT_NO_REPLICATION:
                  opt_no_replication = true;
                  break;

            case OPT_NO_QUICKSUPER:
                  opt_no_quicksuper = true;
                  break;

            case OPT_TRACE:
                  vm_debug = true;
                  break;
#endif

#if defined(ENABLE_DEBUG_FILTER)
            case OPT_FILTER_VERBOSECALL_INCLUDE:
                  opt_filter_verbosecall_include = opt_arg;
                  break;

            case OPT_FILTER_VERBOSECALL_EXCLUDE:
                  opt_filter_verbosecall_exclude = opt_arg;
                  break;

            case OPT_FILTER_SHOW_METHOD:
                  opt_filter_show_method = opt_arg;
                  break;

#endif
            default:
                  printf("Unknown option: %s\n",
                           vm_args->options[opt_index].optionString);
                  usage();
            }
      }

#if defined(ENABLE_JVMTI)
      if (jvmti) {
            jvmti_set_phase(JVMTI_PHASE_ONLOAD);
            jvmti_agentload(agentarg, agentbypath, &handle, &libname);

            if (jdwp)
                  MFREE(agentarg, char, strlen(agentarg));

            jvmti_set_phase(JVMTI_PHASE_PRIMORDIAL);
      }
#endif

      /* initialize this JVM ****************************************************/

      vm_initializing = true;

      /* initialize the garbage collector */

      gc_init(opt_heapmaxsize, opt_heapstartsize);

#if defined(ENABLE_THREADS)
      /* BEFORE: threads_preinit */

      threadlist_init();

      /* AFTER: gc_init (directly after, as this initializes the
         stopworldlock lock */

      threads_preinit();
      lock_init();
#endif

      /* install architecture dependent signal handlers */

      if (!signal_init())
            vm_abort("vm_create: signal_init failed");

#if defined(ENABLE_INTRP)
      /* Allocate main thread stack on the Java heap. */

      if (opt_intrp) {
            intrp_main_stack = GCMNEW(u1, opt_stacksize);
            MSET(intrp_main_stack, 0, u1, opt_stacksize);
      }
#endif

      /* AFTER: threads_preinit */

      if (!string_init())
            vm_abort("vm_create: string_init failed");

      /* AFTER: threads_preinit */

      utf8_init();

      /* AFTER: thread_preinit */

      if (!suck_init())
            vm_abort("vm_create: suck_init failed");

      suck_add_from_property("java.endorsed.dirs");

      /* Now we have all options handled and we can print the version
         information.

         AFTER: suck_add_from_property("java.endorsed.dirs"); */

      if (opt_version)
            version(opt_exit);

      /* AFTER: utf8_init */

      boot_class_path = properties_get("sun.boot.class.path");
      suck_add(boot_class_path);

      /* initialize the classcache hashtable stuff: lock, hashtable
         (must be done _after_ threads_preinit) */

      if (!classcache_init())
            vm_abort("vm_create: classcache_init failed");

      /* Initialize the code memory management. */
      /* AFTER: threads_preinit */

      codememory_init();

      /* initialize the finalizer stuff (must be done _after_
         threads_preinit) */

      if (!finalizer_init())
            vm_abort("vm_create: finalizer_init failed");

      /* Initialize the JIT compiler. */

      jit_init();
      code_init();
      methodtree_init();

#if defined(ENABLE_PYTHON)
      pythonpass_init();
#endif

      /* BEFORE: loader_preinit */

      package_init();

      /* AFTER: utf8_init, classcache_init */

      loader_preinit();
      linker_preinit();

      /* AFTER: loader_preinit, linker_preinit */

      primitive_init();

      loader_init();
      linker_init();

      /* AFTER: loader_init, linker_init */

      primitive_postinit();
      method_init();

#if defined(ENABLE_JIT)
      trap_init();
#endif

      if (!builtin_init())
            vm_abort("vm_create: builtin_init failed");

      /* Initialize the native subsystem. */
      /* BEFORE: threads_init */

      if (!native_init())
            vm_abort("vm_create: native_init failed");

      /* Register the native methods implemented in the VM. */
      /* BEFORE: threads_init */

      nativevm_preinit();

#if defined(ENABLE_JNI)
      /* Initialize the JNI subsystem (must be done _before_
         threads_init, as threads_init can call JNI methods
         (e.g. NewGlobalRef). */

      if (!jni_init())
            vm_abort("vm_create: jni_init failed");
#endif

#if defined(ENABLE_JNI) || defined(ENABLE_HANDLES)
      /* Initialize the local reference table for the main thread. */
      /* BEFORE: threads_init */

      if (!localref_table_init())
            vm_abort("vm_create: localref_table_init failed");
#endif

      /* Iinitialize some important system classes. */
      /* BEFORE: threads_init */

      initialize_init();

#if defined(ENABLE_THREADS)
      threads_init();
#endif

      /* Initialize the native VM subsystem. */
      /* AFTER: threads_init (at least for SUN's classes) */

      nativevm_init();

#if defined(ENABLE_PROFILING)
      /* initialize profiling */

      if (!profile_init())
            vm_abort("vm_create: profile_init failed");
#endif

#if defined(ENABLE_THREADS)
      /* initialize recompilation */

      if (!recompile_init())
            vm_abort("vm_create: recompile_init failed");

      /* start the signal handler thread */

#if defined(__LINUX__)
      /* XXX Remove for exact-GC. */
      if (threads_pthreads_implementation_nptl)
#endif
            if (!signal_start_thread())
                  vm_abort("vm_create: signal_start_thread failed");

      /* finally, start the finalizer thread */

      if (!finalizer_start_thread())
            vm_abort("vm_create: finalizer_start_thread failed");

# if !defined(NDEBUG)
      /* start the memory profiling thread */

      if (opt_ProfileMemoryUsage || opt_ProfileGCMemoryUsage)
            if (!memory_start_thread())
                  vm_abort("vm_create: memory_start_thread failed");
# endif

      /* start the recompilation thread (must be done before the
         profiling thread) */

      if (!recompile_start_thread())
            vm_abort("vm_create: recompile_start_thread failed");

# if defined(ENABLE_PROFILING)
      /* start the profile sampling thread */

/*    if (opt_prof) */
/*          if (!profile_start_thread()) */
/*                vm_abort("vm_create: profile_start_thread failed"); */
# endif
#endif

#if defined(ENABLE_JVMTI)
# if defined(ENABLE_GC_CACAO)
      /* XXX this will not work with the new indirection cells for classloaders!!! */
      assert(0);
# endif
      if (jvmti) {
            /* add agent library to native library hashtable */
            native_hashtable_library_add(utf_new_char(libname), class_java_lang_Object->classloader, handle);
      }
#endif

      /* Increment the number of VMs. */

      vms++;

      /* Initialization is done, VM is created.. */

      vm_created      = true;
      vm_initializing = false;

      /* Print the VM configuration after all stuff is set and the VM is
         initialized. */

      if (opt_PrintConfig)
            vm_printconfig();

      /* everything's ok */

      return true;
}


/* vm_run **********************************************************************

   Runs the main-method of the passed class.

*******************************************************************************/

void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args)
{
      char*                      option;
      char*                      mainname;
      char*                      p;
      utf                       *mainutf;
      classinfo                 *mainclass;
      java_handle_t             *e;
      methodinfo                *m;
      java_handle_objectarray_t *oa; 
      s4                         oalength;
      utf                       *u;
      java_handle_t             *s;
      int                        status;
      int                        i;

      // Prevent compiler warnings.
      oa = NULL;

#if !defined(NDEBUG)
      if (compileall) {
            vm_compile_all();
            return;
      }
#endif

      /* Get the main class plus it's arguments. */

      mainname = NULL;

      if (opt_index < vm_args->nOptions) {
            /* Get main-class argument. */

            mainname = vm_args->options[opt_index].optionString;

            /* If the main class argument is a jar file, put it into the
               classpath. */

            if (opt_jar == true) {
                  p = MNEW(char, strlen(mainname) + strlen("0"));

                  strcpy(p, mainname);

#if defined(ENABLE_JAVASE)
                  properties_add("java.class.path", p);
#endif
            }
            else {
                  /* Replace dots with slashes in the class name. */

                  for (i = 0; i < strlen(mainname); i++)
                        if (mainname[i] == '.')
                              mainname[i] = '/';
            }

            /* Build argument array.  Move index to first argument. */

            opt_index++;

            oalength = vm_args->nOptions - opt_index;

            oa = builtin_anewarray(oalength, class_java_lang_String);

            for (i = 0; i < oalength; i++) {
                  option = vm_args->options[opt_index + i].optionString;

                  u = utf_new_char(option);
                  s = javastring_new(u);

                  array_objectarray_element_set(oa, i, s);
            }
      }

      /* Do we have a main-class argument? */

      if (mainname == NULL)
            usage();

#if !defined(NDEBUG)
      if (opt_method != NULL) {
            vm_compile_method(mainname);
            return;
      }
#endif

      /* set return value to OK */

      status = 0;

      if (opt_jar == true) {
            /* open jar file with java.util.jar.JarFile */

            mainname = vm_get_mainclass_from_jar(mainname);

            if (mainname == NULL)
                  vm_exit(1);
      }

      /* load the main class */

      mainutf = utf_new_char(mainname);

#if defined(ENABLE_JAVAME_CLDC1_1)
      mainclass = load_class_bootstrap(mainutf);
#else
      mainclass = load_class_from_sysloader(mainutf);
#endif

      /* error loading class */

      e = exceptions_get_and_clear_exception();

      if ((e != NULL) || (mainclass == NULL)) {
            exceptions_throw_noclassdeffounderror_cause(e);
            exceptions_print_stacktrace(); 
            vm_exit(1);
      }

      if (!link_class(mainclass)) {
            exceptions_print_stacktrace();
            vm_exit(1);
      }
                  
      /* find the `main' method of the main class */

      m = class_resolveclassmethod(mainclass,
                                                 utf_new_char("main"), 
                                                 utf_new_char("([Ljava/lang/String;)V"),
                                                 class_java_lang_Object,
                                                 false);

      if (exceptions_get_exception()) {
            exceptions_print_stacktrace();
            vm_exit(1);
      }

      /* there is no main method or it isn't static */

      if ((m == NULL) || !(m->flags & ACC_STATIC)) {
            exceptions_clear_exception();
            exceptions_throw_nosuchmethoderror(mainclass,
                                                               utf_new_char("main"), 
                                                               utf_new_char("([Ljava/lang/String;)V"));

            exceptions_print_stacktrace();
            vm_exit(1);
      }

#ifdef TYPEINFO_DEBUG_TEST
      /* test the typeinfo system */
      typeinfo_test();
#endif

#if defined(ENABLE_JVMTI)
      jvmti_set_phase(JVMTI_PHASE_LIVE);
#endif

      /* set ThreadMXBean variables */

      _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++;
      _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++;

      if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount >
            _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount)
            _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount =
                  _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount;

      /* start the main thread */

      (void) vm_call_method(m, NULL, oa);

      /* exception occurred? */

      if (exceptions_get_exception()) {
            exceptions_print_stacktrace();
            status = 1;
      }

#if defined(ENABLE_THREADS)
    /* Detach the main thread so that it appears to have ended when
         the application's main method exits. */

      if (!thread_detach_current_thread())
            vm_abort("vm_run: Could not detach main thread.");
#endif

      /* Destroy the JavaVM. */

      (void) vm_destroy(vm);

      /* And exit. */

      vm_exit(status);
}


/* vm_destroy ******************************************************************

   Unloads a Java VM and reclaims its resources.

*******************************************************************************/

int vm_destroy(JavaVM *vm)
{
#if defined(ENABLE_THREADS)
      /* Create a a trivial new Java waiter thread called
         "DestroyJavaVM". */

      JavaVMAttachArgs args;

      args.name  = "DestroyJavaVM";
      args.group = NULL;

      if (!thread_attach_current_thread(&args, false))
            return 1;

      /* Wait until we are the last non-daemon thread. */

      threads_join_all_threads();
#endif

      /* VM is gone. */

      vm_created = false;

      /* Everything is ok. */

      return 0;
}


/* vm_exit *********************************************************************

   Calls java.lang.System.exit(I)V to exit the JavaVM correctly.

*******************************************************************************/

void vm_exit(s4 status)
{
      methodinfo *m;

      /* signal that we are exiting */

      vm_exiting = true;

      assert(class_java_lang_System);
      assert(class_java_lang_System->state & CLASS_LOADED);

#if defined(ENABLE_JVMTI)
      if (jvmti || (dbgcom!=NULL)) {
            jvmti_set_phase(JVMTI_PHASE_DEAD);
            if (jvmti) jvmti_agentunload();
      }
#endif

      if (!link_class(class_java_lang_System)) {
            exceptions_print_stacktrace();
            exit(1);
      }

      /* call java.lang.System.exit(I)V */

      m = class_resolveclassmethod(class_java_lang_System,
                                                 utf_new_char("exit"),
                                                 utf_int__void,
                                                 class_java_lang_Object,
                                                 true);
      
      if (m == NULL) {
            exceptions_print_stacktrace();
            exit(1);
      }

      /* call the exit function with passed exit status */

      (void) vm_call_method(m, NULL, status);

      /* If we had an exception, just ignore the exception and exit with
         the proper code. */

      vm_shutdown(status);
}


/* vm_shutdown *****************************************************************

   Terminates the system immediately without freeing memory explicitly
   (to be used only for abnormal termination).
      
*******************************************************************************/

void vm_shutdown(s4 status)
{
      if (opt_verbose 
#if defined(ENABLE_STATISTICS)
            || opt_getcompilingtime || opt_stat
#endif
         ) 
      {
            log_text("CACAO terminated by shutdown");
            dolog("Exit status: %d\n", (s4) status);

      }

#if defined(ENABLE_JVMTI)
      /* terminate cacaodbgserver */
      if (dbgcom!=NULL) {
            mutex_lock(&dbgcomlock);
            dbgcom->running=1;
            mutex_unlock(&dbgcomlock);
            jvmti_cacaodbgserver_quit();
      }     
#endif

      exit(status);
}


/* vm_exit_handler *************************************************************

   The exit_handler function is called upon program termination.

   ATTENTION: Don't free system resources here! Some threads may still
   be running as this is called from VMRuntime.exit(). The OS does the
   cleanup for us.

*******************************************************************************/

void vm_exit_handler(void)
{
#if !defined(NDEBUG)
      if (showmethods)
            class_showmethods(mainclass);

      if (showconstantpool)
            class_showconstantpool(mainclass);

      if (showutf)
            utf_show();

# if defined(ENABLE_PROFILING)
      if (opt_prof)
            profile_printstats();
# endif
#endif /* !defined(NDEBUG) */

#if defined(ENABLE_RT_TIMING)
      rt_timing_print_time_stats(stderr);
#endif

#if defined(ENABLE_CYCLES_STATS)
      builtin_print_cycles_stats(stderr);
      stacktrace_print_cycles_stats(stderr);
#endif

      if (opt_verbose 
#if defined(ENABLE_STATISTICS)
            || opt_getcompilingtime || opt_stat
#endif
         ) 
      {
            log_text("CACAO terminated");

#if defined(ENABLE_STATISTICS)
            if (opt_stat) {
                  print_stats();
#ifdef TYPECHECK_STATISTICS
                  typecheck_print_statistics(get_logfile());
#endif
            }

            if (opt_getcompilingtime)
                  print_times();
#endif /* defined(ENABLE_STATISTICS) */
      }
      /* vm_print_profile(stderr);*/
}


/* vm_abort ********************************************************************

   Prints an error message and aborts the VM.

   IN:
       text ... error message to print

*******************************************************************************/

void vm_abort(const char *text, ...)
{
      va_list ap;

      /* Print the log message. */

      log_start();

      va_start(ap, text);
      log_vprint(text, ap);
      va_end(ap);

      log_finish();

      /* Now abort the VM. */

      system_abort();
}


/* vm_abort_errnum *************************************************************

   Prints an error message, appends ":" plus the strerror-message of
   errnum and aborts the VM.

   IN:
       errnum ... error number
       text ..... error message to print

*******************************************************************************/

void vm_abort_errnum(int errnum, const char *text, ...)
{
      va_list ap;

      /* Print the log message. */

      log_start();

      va_start(ap, text);
      log_vprint(text, ap);
      va_end(ap);

      /* Print the strerror-message of errnum. */

      log_print(": %s", system_strerror(errnum));

      log_finish();

      /* Now abort the VM. */

      system_abort();
}


/* vm_abort_errno **************************************************************

   Equal to vm_abort_errnum, but uses errno to get the error number.

   IN:
       text ... error message to print

*******************************************************************************/

void vm_abort_errno(const char *text, ...)
{
      va_list ap;

      va_start(ap, text);
      vm_abort_errnum(errno, text, ap);
      va_end(ap);
}


/* vm_abort_disassemble ********************************************************

   Prints an error message, disassemble the given code range (if
   enabled) and aborts the VM.

   IN:
       pc.......PC to disassemble
         count....number of instructions to disassemble

*******************************************************************************/

void vm_abort_disassemble(void *pc, int count, const char *text, ...)
{
      va_list ap;
#if defined(ENABLE_DISASSEMBLER)
      int     i;
#endif

      /* Print debug message. */

      log_start();

      va_start(ap, text);
      log_vprint(text, ap);
      va_end(ap);

      log_finish();

      /* Print the PC. */

#if SIZEOF_VOID_P == 8
      log_println("PC=0x%016lx", pc);
#else
      log_println("PC=0x%08x", pc);
#endif

#if defined(ENABLE_DISASSEMBLER)
      log_println("machine instructions at PC:");

      /* Disassemble the given number of instructions. */

      for (i = 0; i < count; i++)
            pc = disassinstr(pc);
#endif

      vm_abort("Aborting...");
}


/* vm_get_mainclass_from_jar ***************************************************

   Gets the name of the main class from a JAR's manifest file.

*******************************************************************************/

static char *vm_get_mainclass_from_jar(char *mainname)
{
      classinfo     *c;
      java_handle_t *o;
      methodinfo    *m;
      java_handle_t *s;

      c = load_class_from_sysloader(utf_new_char("java/util/jar/JarFile"));

      if (c == NULL) {
            exceptions_print_stacktrace();
            return NULL;
      }

      /* create JarFile object */

      o = builtin_new(c);

      if (o == NULL) {
            exceptions_print_stacktrace();
            return NULL;
      }

      m = class_resolveclassmethod(c,
                                                 utf_init, 
                                                 utf_java_lang_String__void,
                                                 class_java_lang_Object,
                                                 true);

      if (m == NULL) {
            exceptions_print_stacktrace();
            return NULL;
      }

      s = javastring_new_from_ascii(mainname);

      (void) vm_call_method(m, o, s);

      if (exceptions_get_exception()) {
            exceptions_print_stacktrace();
            return NULL;
      }

      /* get manifest object */

      m = class_resolveclassmethod(c,
                                                 utf_new_char("getManifest"), 
                                                 utf_new_char("()Ljava/util/jar/Manifest;"),
                                                 class_java_lang_Object,
                                                 true);

      if (m == NULL) {
            exceptions_print_stacktrace();
            return NULL;
      }

      o = vm_call_method(m, o);

      if (o == NULL) {
            fprintf(stderr, "Could not get manifest from %s (invalid or corrupt jarfile?)\n", mainname);
            return NULL;
      }


      /* get Main Attributes */

      LLNI_class_get(o, c);

      m = class_resolveclassmethod(c,
                                                 utf_new_char("getMainAttributes"), 
                                                 utf_new_char("()Ljava/util/jar/Attributes;"),
                                                 class_java_lang_Object,
                                                 true);

      if (m == NULL) {
            exceptions_print_stacktrace();
            return NULL;
      }

      o = vm_call_method(m, o);

      if (o == NULL) {
            fprintf(stderr, "Could not get main attributes from %s (invalid or corrupt jarfile?)\n", mainname);
            return NULL;
      }


      /* get property Main-Class */

      LLNI_class_get(o, c);

      m = class_resolveclassmethod(c,
                                                 utf_new_char("getValue"), 
                                                 utf_new_char("(Ljava/lang/String;)Ljava/lang/String;"),
                                                 class_java_lang_Object,
                                                 true);

      if (m == NULL) {
            exceptions_print_stacktrace();
            return NULL;
      }

      s = javastring_new_from_ascii("Main-Class");

      o = vm_call_method(m, o, s);

      if (o == NULL) {
            fprintf(stderr, "Failed to load Main-Class manifest attribute from\n");
            fprintf(stderr, "%s\n", mainname);
            return NULL;
      }

      return javastring_tochar(o);
}


/* vm_compile_all **************************************************************

   Compile all methods found in the bootclasspath.

*******************************************************************************/

#if !defined(NDEBUG)
static void vm_compile_all(void)
{
      classinfo              *c;
      methodinfo             *m;
      u4                      slot;
      classcache_name_entry  *nmen;
      classcache_class_entry *clsen;
      s4                      i;

      /* create all classes found in the bootclasspath */
      /* XXX currently only works with zip/jar's */

      loader_load_all_classes();

      /* link all classes */

      for (slot = 0; slot < hashtable_classcache.size; slot++) {
            nmen = (classcache_name_entry *) hashtable_classcache.ptr[slot];

            for (; nmen; nmen = nmen->hashlink) {
                  /* iterate over all class entries */

                  for (clsen = nmen->classes; clsen; clsen = clsen->next) {
                        c = clsen->classobj;

                        if (c == NULL)
                              continue;

                        if (!(c->state & CLASS_LINKED)) {
                              if (!link_class(c)) {
                                    fprintf(stderr, "Error linking: ");
                                    utf_fprint_printable_ascii_classname(stderr, c->name);
                                    fprintf(stderr, "\n");

                                    /* print out exception and cause */

                                    exceptions_print_current_exception();

                                    /* goto next class */

                                    continue;
                              }
                        }

                        /* compile all class methods */

                        for (i = 0; i < c->methodscount; i++) {
                              m = &(c->methods[i]);

                              if (m->jcode != NULL) {
                                    if (!jit_compile(m)) {
                                          fprintf(stderr, "Error compiling: ");
                                          utf_fprint_printable_ascii_classname(stderr, c->name);
                                          fprintf(stderr, ".");
                                          utf_fprint_printable_ascii(stderr, m->name);
                                          utf_fprint_printable_ascii(stderr, m->descriptor);
                                          fprintf(stderr, "\n");

                                          /* print out exception and cause */

                                          exceptions_print_current_exception();
                                    }
                              }
                        }
                  }
            }
      }
}
#endif /* !defined(NDEBUG) */


/* vm_compile_method ***********************************************************

   Compile a specific method.

*******************************************************************************/

#if !defined(NDEBUG)
static void vm_compile_method(char* mainname)
{
      methodinfo *m;

      /* create, load and link the main class */

      mainclass = load_class_bootstrap(utf_new_char(mainname));

      if (mainclass == NULL)
            exceptions_print_stacktrace();

      if (!link_class(mainclass))
            exceptions_print_stacktrace();

      if (opt_signature != NULL) {
            m = class_resolveclassmethod(mainclass,
                                                       utf_new_char(opt_method),
                                                       utf_new_char(opt_signature),
                                                       mainclass,
                                                       false);
      }
      else {
            m = class_resolveclassmethod(mainclass,
                                                       utf_new_char(opt_method),
                                                       NULL,
                                                       mainclass,
                                                       false);
      }

      if (m == NULL)
            vm_abort("vm_compile_method: java.lang.NoSuchMethodException: %s.%s",
                         opt_method, opt_signature ? opt_signature : "");
            
      jit_compile(m);
}
#endif /* !defined(NDEBUG) */


/* vm_call_array ***************************************************************

   Calls a Java method with a variable number of arguments, passed via
   an argument array.

   ATTENTION: This function has to be used outside the nativeworld.

*******************************************************************************/

#define VM_CALL_ARRAY(name, type)                                 \
static type vm_call##name##_array(methodinfo *m, uint64_t *array) \
{                                                                 \
      methoddesc *md;                                               \
      void       *pv;                                               \
      type        value;                                            \
                                                                  \
      assert(m->code != NULL);                                      \
                                                                  \
      md = m->parseddesc;                                           \
      pv = m->code->entrypoint;                                     \
                                                                  \
      STATISTICS(count_calls_native_to_java++);                     \
                                                                  \
      value = asm_vm_call_method##name(pv, array, md->memuse);      \
                                                                  \
      return value;                                                 \
}

static java_handle_t *vm_call_array(methodinfo *m, uint64_t *array)
{
      methoddesc    *md;
      void          *pv;
      java_object_t *o;

      assert(m->code != NULL);

      md = m->parseddesc;
      pv = m->code->entrypoint;

      STATISTICS(count_calls_native_to_java++);

      o = asm_vm_call_method(pv, array, md->memuse);

      if (md->returntype.type == TYPE_VOID)
            o = NULL;

      return LLNI_WRAP(o);
}

VM_CALL_ARRAY(_int,    int32_t)
VM_CALL_ARRAY(_long,   int64_t)
VM_CALL_ARRAY(_float,  float)
VM_CALL_ARRAY(_double, double)


/* vm_call_method **************************************************************

   Calls a Java method with a variable number of arguments.

*******************************************************************************/

#define VM_CALL_METHOD(name, type)                                  \
type vm_call_method##name(methodinfo *m, java_handle_t *o, ...)     \
{                                                                   \
      va_list ap;                                                     \
      type    value;                                                  \
                                                                    \
      va_start(ap, o);                                                \
      value = vm_call_method##name##_valist(m, o, ap);                \
      va_end(ap);                                                     \
                                                                    \
      return value;                                                   \
}

VM_CALL_METHOD(,        java_handle_t *)
VM_CALL_METHOD(_int,    int32_t)
VM_CALL_METHOD(_long,   int64_t)
VM_CALL_METHOD(_float,  float)
VM_CALL_METHOD(_double, double)


/* vm_call_method_valist *******************************************************

   Calls a Java method with a variable number of arguments, passed via
   a va_list.

*******************************************************************************/

#define VM_CALL_METHOD_VALIST(name, type)                               \
type vm_call_method##name##_valist(methodinfo *m, java_handle_t *o,     \
                                                   va_list ap)                          \
{                                                                       \
      uint64_t *array;                                                    \
      type      value;                                                    \
      int32_t   dumpmarker;                                               \
                                                                        \
      if (m->code == NULL)                                                \
            if (!jit_compile(m))                                            \
                  return 0;                                                   \
                                                                        \
      THREAD_NATIVEWORLD_EXIT;                                            \
      DMARKER;                                                            \
                                                                        \
      array = argument_vmarray_from_valist(m, o, ap);                     \
      value = vm_call##name##_array(m, array);                            \
                                                                        \
      DRELEASE;                                                           \
      THREAD_NATIVEWORLD_ENTER;                                           \
                                                                        \
      return value;                                                       \
}

VM_CALL_METHOD_VALIST(,        java_handle_t *)
VM_CALL_METHOD_VALIST(_int,    int32_t)
VM_CALL_METHOD_VALIST(_long,   int64_t)
VM_CALL_METHOD_VALIST(_float,  float)
VM_CALL_METHOD_VALIST(_double, double)


/* vm_call_method_jvalue *******************************************************

   Calls a Java method with a variable number of arguments, passed via
   a jvalue array.

*******************************************************************************/

#define VM_CALL_METHOD_JVALUE(name, type)                               \
type vm_call_method##name##_jvalue(methodinfo *m, java_handle_t *o,     \
                                               const jvalue *args)                  \
{                                                                       \
      uint64_t *array;                                                    \
      type      value;                                                    \
      int32_t   dumpmarker;                                               \
                                                                        \
      if (m->code == NULL)                                                \
            if (!jit_compile(m))                                            \
                  return 0;                                                   \
                                                                        \
      THREAD_NATIVEWORLD_EXIT;                                            \
      DMARKER;                                                            \
                                                                        \
      array = argument_vmarray_from_jvalue(m, o, args);                   \
      value = vm_call##name##_array(m, array);                            \
                                                                        \
      DRELEASE;                                                           \
      THREAD_NATIVEWORLD_ENTER;                                           \
                                                                        \
      return value;                                                       \
}

VM_CALL_METHOD_JVALUE(,        java_handle_t *)
VM_CALL_METHOD_JVALUE(_int,    int32_t)
VM_CALL_METHOD_JVALUE(_long,   int64_t)
VM_CALL_METHOD_JVALUE(_float,  float)
VM_CALL_METHOD_JVALUE(_double, double)


/* vm_call_method_objectarray **************************************************

   Calls a Java method with a variable number if arguments, passed via
   an objectarray of boxed values. Returns a boxed value.

*******************************************************************************/

java_handle_t *vm_call_method_objectarray(methodinfo *m, java_handle_t *o,
                                                              java_handle_objectarray_t *params)
{
      uint64_t      *array;
      java_handle_t *xptr;
      java_handle_t *ro;
      imm_union      value;
      int32_t        dumpmarker;

      /* Prevent compiler warnings. */

      ro = NULL;

      /* compile methods which are not yet compiled */

      if (m->code == NULL)
            if (!jit_compile(m))
                  return NULL;

      /* leave the nativeworld */

      THREAD_NATIVEWORLD_EXIT;

      /* mark start of dump memory area */

      DMARKER;

      /* Fill the argument array from a object-array. */

      array = argument_vmarray_from_objectarray(m, o, params);

      if (array == NULL) {
            /* release dump area */

            DRELEASE;

            /* enter the nativeworld again */

            THREAD_NATIVEWORLD_ENTER;

            exceptions_throw_illegalargumentexception();

            return NULL;
      }

      switch (m->parseddesc->returntype.decltype) {
      case PRIMITIVETYPE_VOID:
            value.a = vm_call_array(m, array);
            break;

      case PRIMITIVETYPE_BOOLEAN:
      case PRIMITIVETYPE_BYTE:
      case PRIMITIVETYPE_CHAR:
      case PRIMITIVETYPE_SHORT:
      case PRIMITIVETYPE_INT:
            value.i = vm_call_int_array(m, array);
            break;

      case PRIMITIVETYPE_LONG:
            value.l = vm_call_long_array(m, array);
            break;

      case PRIMITIVETYPE_FLOAT:
            value.f = vm_call_float_array(m, array);
            break;

      case PRIMITIVETYPE_DOUBLE:
            value.d = vm_call_double_array(m, array);
            break;

      case TYPE_ADR:
            ro = vm_call_array(m, array);
            break;

      default:
            vm_abort("vm_call_method_objectarray: invalid return type %d", m->parseddesc->returntype.decltype);
      }

      /* release dump area */

      DRELEASE;

      /* enter the nativeworld again */

      THREAD_NATIVEWORLD_ENTER;

      /* box the return value if necesarry */

      if (m->parseddesc->returntype.decltype != TYPE_ADR)
            ro = primitive_box(m->parseddesc->returntype.decltype, value);

      /* check for an exception */

      xptr = exceptions_get_exception();

      if (xptr != NULL) {
            /* clear exception pointer, we are calling JIT code again */

            exceptions_clear_exception();

            exceptions_throw_invocationtargetexception(xptr);
      }

      return ro;
}


/*
 * 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:
 */

Generated by  Doxygen 1.6.0   Back to index