* src/vm/jit/verify/typecheck.c (verify_fieldaccess): New function.
[cacao.git] / src / vm / vm.c
index e0e34793adf288e6e5645f7f40b3ccba3d8ba537..3179ea7579250e4bc047203ddf602c6bcb93e946 100644 (file)
 #include "config.h"
 
 #include <assert.h>
+#include <errno.h>
 #include <stdlib.h>
 
+#if defined(WITH_JRE_LAYOUT)
+# include <libgen.h>
+# include <unistd.h>
+#endif
+
 #include "vm/types.h"
 
 #include "mm/boehm.h"
@@ -49,7 +55,6 @@
 # include "threads/native/threads.h"
 #endif
 
-#include "toolbox/util.h"
 #include "vm/classcache.h"
 #include "vm/exceptions.h"
 #include "vm/finalizer.h"
@@ -87,11 +92,11 @@ s4 vms = 0;                             /* number of VMs created              */
 bool vm_initializing = false;
 bool vm_exiting = false;
 
-#if defined(ENABLE_INTRP)
-u1 *intrp_main_stack = NULL;
-#endif
+char      *cacao_prefix = NULL;
+char      *cacao_libjvm = NULL;
+char      *classpath_libdir = NULL;
 
-char *mainstring = NULL;
+char      *mainstring = NULL;
 classinfo *mainclass = NULL;
 
 char *specificmethodname = NULL;
@@ -99,6 +104,10 @@ char *specificsignature = NULL;
 
 bool startit = true;
 
+#if defined(ENABLE_INTRP)
+u1 *intrp_main_stack = NULL;
+#endif
+
 
 /* define heap sizes **********************************************************/
 
@@ -165,10 +174,14 @@ enum {
        OPT_LOG,
        OPT_CHECK,
        OPT_LOAD,
-       OPT_METHOD,
-       OPT_SIGNATURE,
        OPT_SHOW,
+       OPT_DEBUGCOLOR,
+
+#if !defined(NDEBUG)
        OPT_ALL,
+       OPT_METHOD,
+       OPT_SIGNATURE,
+#endif
 
 #if defined(ENABLE_VERIFIER)
        OPT_NOVERIFY,
@@ -271,8 +284,12 @@ opt_struct opts[] = {
        { "c",                 true,  OPT_CHECK },
        { "l",                 false, OPT_LOAD },
        { "eager",             false, OPT_EAGER },
-       { "sig",               true,  OPT_SIGNATURE },
+
+#if !defined(NDEBUG)
        { "all",               false, OPT_ALL },
+       { "sig",               true,  OPT_SIGNATURE },
+#endif
+
 #if defined(ENABLE_LOOP)
        { "oloop",             false, OPT_OLOOP },
 #endif
@@ -328,8 +345,13 @@ opt_struct opts[] = {
 #if defined(ENABLE_INLINING)
        { "i",                 true,  OPT_INLINING },
 #endif
+
+#if !defined(NDEBUG)
        { "m",                 true,  OPT_METHOD },
+#endif
+
        { "s",                 true,  OPT_SHOW },
+       { "debug-color",      false,  OPT_DEBUGCOLOR },
 
        { NULL,                false, 0 }
 };
@@ -381,6 +403,7 @@ void usage(void)
        puts("    -v                       write state-information");
        puts("    -verbose[:call|exception|jit]");
        puts("                             enable specific verbose output");
+       puts("    -debug-color             colored output for ANSI terms");
 #ifdef TYPECHECK_VERBOSE
        puts("    -verbosetc               write debug messages while typechecking");
 #endif
@@ -403,9 +426,12 @@ void usage(void)
 #endif
        puts("    -l                       don't start the class after loading");
        puts("    -eager                   perform eager class loading and linking");
+#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(how)...               show...");
        puts("           c(onstants)       the constant pool");
        puts("           m(ethods)         class fields and methods");
@@ -511,17 +537,18 @@ static void version(bool opt_exit)
        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);
-       puts("  java.boot.class.path: "CACAO_VM_ZIP":"CLASSPATH_GLIBJ_ZIP"");
-       puts("  java.library.path   : "CLASSPATH_LIBRARY_PATH"\n");
+       printf("  maximum heap size              : %d\n", HEAP_MAXSIZE);
+       printf("  initial heap size              : %d\n", HEAP_STARTSIZE);
+       printf("  stack size                     : %d\n", STACK_SIZE);
+       puts("  java.boot.class.path           : "CACAO_VM_ZIP":"CLASSPATH_GLIBJ_ZIP"");
+       puts("  gnu.classpath.boot.library.path: "CLASSPATH_LIBDIR"/classpath\n");
 
        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);
-       printf("  java.boot.class.path: %s\n", bootclasspath);
+       printf("  maximum heap size              : %d\n", opt_heapmaxsize);
+       printf("  initial heap size              : %d\n", opt_heapstartsize);
+       printf("  stack size                     : %d\n", opt_stacksize);
+       printf("  java.boot.class.path           : %s\n", bootclasspath);
+       printf("  gnu.classpath.boot.library.path: %s\n", classpath_libdir);
 
        /* exit normally, if requested */
 
@@ -547,6 +574,15 @@ static void fullversion(void)
 }
 
 
+/* 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(void);
+#endif
+
+
 /* vm_create *******************************************************************
 
    Creates a JVM.  Called by JNI_CreateJavaVM.
@@ -586,9 +622,15 @@ bool vm_create(JavaVMInitArgs *vm_args)
        if (vms > 0)
                return false;
 
+       if (atexit(vm_exit_handler))
+               vm_abort("atexit failed: %s\n", strerror(errno));
+
+       if (opt_verbose)
+               log_text("CACAO started -------------------------------------------------------");
+
        /* set the VM starttime */
 
-       _Jv_jvm->starttime = util_current_time_millis();
+       _Jv_jvm->starttime = builtin_currenttimemillis();
 
        /* get stuff from the environment *****************************************/
 
@@ -596,15 +638,71 @@ bool vm_create(JavaVMInitArgs *vm_args)
        nogc_init(HEAP_MAXSIZE, HEAP_STARTSIZE);
 #endif
 
+#if defined(WITH_JRE_LAYOUT)
+       /* SUN also uses a buffer of 4096-bytes (strace is your friend). */
+
+       cacao_prefix = MNEW(char, 4096);
+
+       if (readlink("/proc/self/exe", cacao_prefix, 4095) == -1)
+               vm_abort("readlink failed: %s\n", strerror(errno));
+
+       /* get the path of the current executable */
+
+       cacao_prefix = dirname(cacao_prefix);
+
+       if ((strlen(cacao_prefix) + strlen("/..") + strlen("0")) > 4096)
+               vm_abort("libjvm name to long for buffer\n");
+
+       /* concatenate the library name */
+
+       strcat(cacao_prefix, "/..");
+
+       /* now set path to libjvm.so */
+
+       len = strlen(cacao_prefix) + strlen("/lib/libjvm") + strlen("0");
+
+       cacao_libjvm = MNEW(char, len);
+       strcpy(cacao_libjvm, cacao_prefix);
+       strcat(cacao_libjvm, "/lib/libjvm");
+
+       /* and finally set the path to GNU Classpath libraries */
+
+       len = strlen(cacao_prefix) + strlen("/lib/classpath") + strlen("0");
+
+       classpath_libdir = MNEW(char, len);
+       strcpy(classpath_libdir, cacao_prefix);
+       strcat(classpath_libdir, "/lib/classpath");
+#else
+       cacao_prefix     = CACAO_PREFIX;
+       cacao_libjvm     = CACAO_LIBDIR"/libjvm";
+       classpath_libdir = CLASSPATH_LIBDIR"/classpath";
+#endif
+
        /* set the bootclasspath */
 
        cp = getenv("BOOTCLASSPATH");
 
-       if (cp) {
+       if (cp != NULL) {
                bootclasspath = MNEW(char, strlen(cp) + strlen("0"));
                strcpy(bootclasspath, cp);
+       }
+       else {
+#if defined(WITH_JRE_LAYOUT)
+               len =
+                       strlen(cacao_prefix) +
+                       strlen("/share/cacao/vm.zip") +
+                       strlen(":") +
+                       strlen(cacao_prefix) +
+                       strlen("/share/classpath/glibj.zip") +
+                       strlen("0");
 
-       } else {
+               bootclasspath = MNEW(char, len);
+               strcat(bootclasspath, cacao_prefix);
+               strcat(bootclasspath, "/share/cacao/vm.zip");
+               strcat(bootclasspath, ":");
+               strcat(bootclasspath, cacao_prefix);
+               strcat(bootclasspath, "/share/classpath/glibj.zip");
+#else
                len = strlen(CACAO_VM_ZIP) +
                        strlen(":") +
                        strlen(CLASSPATH_GLIBJ_ZIP) +
@@ -614,17 +712,18 @@ bool vm_create(JavaVMInitArgs *vm_args)
                strcat(bootclasspath, CACAO_VM_ZIP);
                strcat(bootclasspath, ":");
                strcat(bootclasspath, CLASSPATH_GLIBJ_ZIP);
+#endif
        }
 
        /* set the classpath */
 
        cp = getenv("CLASSPATH");
 
-       if (cp) {
+       if (cp != NULL) {
                classpath = MNEW(char, strlen(cp) + strlen("0"));
                strcat(classpath, cp);
-
-       else {
+       }
+       else {
                classpath = MNEW(char, strlen(".") + strlen("0"));
                strcpy(classpath, ".");
        }
@@ -658,7 +757,6 @@ bool vm_create(JavaVMInitArgs *vm_args)
 
        properties_add("java.endorsed.dirs", ""CACAO_PREFIX"/jre/lib/endorsed");
 
-
        /* iterate over all passed options */
 
        while ((opt = options_get(opts, vm_args)) != OPT_DONE) {
@@ -859,6 +957,9 @@ bool vm_create(JavaVMInitArgs *vm_args)
                        else if (strcmp("exception", opt_arg) == 0)
                                opt_verboseexception = true;
                        break;
+               case OPT_DEBUGCOLOR:
+                       opt_debugcolor = true;
+                       break;
 
 #if defined(ENABLE_VERIFIER) && defined(TYPECHECK_VERBOSE)
                case OPT_VERBOSETC:
@@ -932,22 +1033,24 @@ bool vm_create(JavaVMInitArgs *vm_args)
                        opt_eager = true;
                        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;
-                       
-               case OPT_ALL:
-                       compileall = true;
-                       opt_run = false;
-                       makeinitializations = false;
-                       break;
-                       
+#endif
+
                case OPT_SHOW:       /* Display options */
                        for (j = 0; j < strlen(opt_arg); j++) {         
                                switch (opt_arg[j]) {
@@ -1094,6 +1197,10 @@ bool vm_create(JavaVMInitArgs *vm_args)
                case OPT_INTRP:
 #if defined(ENABLE_INTRP)
                        opt_intrp = true;
+#if defined(ENABLE_VERIFIER)
+                       /* XXX currently the verifier does not work with the interpreter */
+                       opt_verify = false;
+#endif
 #else
                        printf("-Xint option not enabled.\n");
                        exit(1);
@@ -1154,8 +1261,8 @@ bool vm_create(JavaVMInitArgs *vm_args)
                        classpath = MNEW(char, strlen(mainstring) + strlen("0"));
 
                        strcpy(classpath, mainstring);
-               
-               else {
+               }
+               else {
                        /* replace .'s with /'s in classname */
 
                        for (i = strlen(mainstring) - 1; i >= 0; i--)
@@ -1355,6 +1462,140 @@ bool vm_create(JavaVMInitArgs *vm_args)
 }
 
 
+/* vm_run **********************************************************************
+
+   Runs the main-method of the passed class.
+
+*******************************************************************************/
+
+void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args)
+{
+       utf              *mainutf;
+       classinfo        *mainclass;
+       methodinfo       *m;
+       java_objectarray *oa; 
+       s4                oalength;
+       utf              *u;
+       java_lang_String *s;
+       s4                status;
+       s4                i;
+
+#if !defined(NDEBUG)
+       if (compileall) {
+               vm_compile_all();
+               return;
+       }
+
+       if (opt_method != NULL) {
+               vm_compile_method();
+               return;
+       }
+#endif /* !defined(NDEBUG) */
+
+       /* should we run the main-method? */
+
+       if (mainstring == NULL)
+               usage();
+
+       /* set return value to OK */
+
+       status = 0;
+
+       if (opt_jar == true)
+               /* open jar file with java.util.jar.JarFile */
+               mainstring = vm_get_mainclass_from_jar(mainstring);
+
+       /* load the main class */
+
+       mainutf = utf_new_char(mainstring);
+
+       if (!(mainclass = load_class_from_sysloader(mainutf)))
+               throw_main_exception_exit();
+
+       /* error loading class, clear exceptionptr for new exception */
+
+       if (*exceptionptr || !mainclass) {
+               /*                      *exceptionptr = NULL; */
+
+               /*                      *exceptionptr = */
+               /*                              new_exception_message(string_java_lang_NoClassDefFoundError, */
+               /*                                                                        mainstring); */
+               throw_main_exception_exit();
+       }
+
+       if (!link_class(mainclass))
+               throw_main_exception_exit();
+                       
+       /* 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 (*exceptionptr) {
+               throw_main_exception_exit();
+       }
+
+       /* there is no main method or it isn't static */
+
+       if ((m == NULL) || !(m->flags & ACC_STATIC)) {
+               *exceptionptr = NULL;
+
+               *exceptionptr =
+                       new_exception_message(string_java_lang_NoSuchMethodError, "main");
+               throw_main_exception_exit();
+       }
+
+       /* build argument array */
+
+       oalength = vm_args->nOptions - opt_index;
+
+       oa = builtin_anewarray(oalength, class_java_lang_String);
+
+       for (i = 0; i < oalength; i++) {
+               u = utf_new_char(vm_args->options[opt_index + i].optionString);
+               s = javastring_new(u);
+
+               oa->data[i] = (java_objectheader *) s;
+       }
+
+#ifdef TYPEINFO_DEBUG_TEST
+       /* test the typeinfo system */
+       typeinfo_test();
+#endif
+       /*class_showmethods(currentThread->group->header.vftbl->class); */
+
+#if defined(ENABLE_JVMTI)
+       jvmti_set_phase(JVMTI_PHASE_LIVE);
+#endif
+
+       /* increase total started thread count */
+
+       _Jv_jvm->total_started_thread_count++;
+
+       /* start the main thread */
+
+       (void) vm_call_method(m, NULL, oa);
+
+       /* exception occurred? */
+
+       if (*exceptionptr) {
+               throw_main_exception();
+               status = 1;
+       }
+
+       /* unload the JavaVM */
+
+       vm_destroy(vm);
+
+       /* and exit */
+
+       vm_exit(status);
+}
+
+
 /* vm_destroy ******************************************************************
 
    Unloads a Java VM and reclaims its resources.
@@ -1545,6 +1786,237 @@ void vm_abort(const char *text, ...)
 }
 
 
+/* 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 *mainstring)
+{
+       classinfo         *c;
+       java_objectheader *o;
+       methodinfo        *m;
+       java_lang_String  *s;
+
+       c = load_class_from_sysloader(utf_new_char("java/util/jar/JarFile"));
+
+       if (c == NULL)
+               throw_main_exception_exit();
+       
+       /* create JarFile object */
+
+       o = builtin_new(c);
+
+       if (o == NULL)
+               throw_main_exception_exit();
+
+
+       m = class_resolveclassmethod(c,
+                                                                utf_init, 
+                                                                utf_java_lang_String__void,
+                                                                class_java_lang_Object,
+                                                                true);
+
+       if (m == NULL)
+               throw_main_exception_exit();
+
+       s = javastring_new_from_ascii(mainstring);
+
+       (void) vm_call_method(m, o, s);
+
+       if (*exceptionptr)
+               throw_main_exception_exit();
+
+       /* 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)
+               throw_main_exception_exit();
+
+       o = vm_call_method(m, o);
+
+       if (o == NULL) {
+               fprintf(stderr, "Could not get manifest from %s (invalid or corrupt jarfile?)\n", mainstring);
+               vm_exit(1);
+       }
+
+
+       /* get Main Attributes */
+
+       m = class_resolveclassmethod(o->vftbl->class,
+                                                                utf_new_char("getMainAttributes"), 
+                                                                utf_new_char("()Ljava/util/jar/Attributes;"),
+                                                                class_java_lang_Object,
+                                                                true);
+
+       if (m == NULL)
+               throw_main_exception_exit();
+
+       o = vm_call_method(m, o);
+
+       if (o == NULL) {
+               fprintf(stderr, "Could not get main attributes from %s (invalid or corrupt jarfile?)\n", mainstring);
+               vm_exit(1);
+       }
+
+
+       /* get property Main-Class */
+
+       m = class_resolveclassmethod(o->vftbl->class,
+                                                                utf_new_char("getValue"), 
+                                                                utf_new_char("(Ljava/lang/String;)Ljava/lang/String;"),
+                                                                class_java_lang_Object,
+                                                                true);
+
+       if (m == NULL)
+               throw_main_exception_exit();
+
+       s = javastring_new_from_ascii("Main-Class");
+
+       o = vm_call_method(m, o, s);
+
+       if (o == NULL)
+               throw_main_exception_exit();
+
+       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_exception(*exceptionptr);
+
+                                               /* 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_exception(*exceptionptr);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* vm_compile_method ***********************************************************
+
+   Compile a specific method.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+static void vm_compile_method(void)
+{
+       methodinfo *m;
+
+       /* create, load and link the main class */
+
+       if (!(mainclass = load_class_bootstrap(utf_new_char(mainstring))))
+               throw_main_exception_exit();
+
+       if (!link_class(mainclass))
+               throw_main_exception_exit();
+
+       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) {
+               char message[MAXLOGTEXT];
+               sprintf(message, "%s%s", opt_method,
+                               opt_signature ? opt_signature : "");
+
+               *exceptionptr =
+                       new_exception_message(string_java_lang_NoSuchMethodException,
+                                                                 message);
+                                                                                
+               throw_main_exception_exit();
+       }
+               
+       jit_compile(m);
+}
+#endif /* !defined(NDEBUG) */
+
+
 /* vm_vmargs_from_valist *******************************************************
 
    XXX