/* src/vm/exceptions.c - exception related functions
- Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
- C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
- E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
- J. Wenninger, Institut f. Computersprachen - TU Wien
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <unistd.h>
#include <sys/mman.h>
#include "vm/types.h"
#include "native/native.h"
#include "native/include/java_lang_String.h"
+#include "native/include/java_lang_Thread.h"
#include "native/include/java_lang_Throwable.h"
#include "threads/lock-common.h"
-#include "threads/threads-common.h"
+#include "threads/thread.h"
#include "toolbox/util.h"
#include "vmcore/loader.h"
#include "vmcore/method.h"
#include "vmcore/options.h"
+#include "vmcore/system.h"
#if defined(ENABLE_VMLOG)
#include <vmlog_cacao.h>
/* mmap a memory page at address 0x0, so our hardware-exceptions
work. */
- pagesize = getpagesize();
+ pagesize = system_getpagesize();
- (void) memory_mmap_anon(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
+ (void) system_mmap_anonymous(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
#endif
+ TRACESUBSYSTEMINITIALIZATION("exceptions_init");
+
/* check if we get into trouble with our hardware-exceptions */
if (OFFSET(java_bytearray_t, data) <= EXCEPTION_HARDWARE_LARGEST)
}
+/* exceptions_new_class_utf ****************************************************
+
+ Creates an exception object with the given class and initalizes it
+ with the given utf message.
+
+ IN:
+ c ......... exception class
+ message ... the message as an utf *
+
+ RETURN VALUE:
+ an exception pointer (in any case -- either it is the newly
+ created exception, or an exception thrown while trying to create
+ it).
+
+*******************************************************************************/
+
+static java_handle_t *exceptions_new_class_utf(classinfo *c, utf *message)
+{
+ java_handle_t *s;
+ java_handle_t *o;
+
+ if (vm_initializing)
+ exceptions_abort(c->name, message);
+
+ s = javastring_new(message);
+
+ if (s == NULL)
+ return exceptions_get_exception();
+
+ o = native_new_and_init_string(c, s);
+
+ if (o == NULL)
+ return exceptions_get_exception();
+
+ return o;
+}
+
+
/* exceptions_new_utf **********************************************************
Creates an exception object with the given name and initalizes it.
}
+/* exceptions_new_utf_javastring ***********************************************
+
+ Creates an exception object with the given name and initalizes it
+ with the given java/lang/String message.
+
+ IN:
+ classname....class name in UTF-8
+ message......the message as a java.lang.String
+
+ RETURN VALUE:
+ an exception pointer (in any case -- either it is the newly created
+ exception, or an exception thrown while trying to create it).
+
+*******************************************************************************/
+
+static java_handle_t *exceptions_new_utf_javastring(utf *classname,
+ java_handle_t *message)
+{
+ java_handle_t *o;
+ classinfo *c;
+
+ if (vm_initializing)
+ exceptions_abort(classname, NULL);
+
+ c = load_class_bootstrap(classname);
+
+ if (c == NULL)
+ return exceptions_get_exception();
+
+ o = native_new_and_init_string(c, message);
+
+ if (o == NULL)
+ return exceptions_get_exception();
+
+ return o;
+}
+
+
+/* exceptions_new_utf_utf ******************************************************
+
+ Creates an exception object with the given name and initalizes it
+ with the given utf message.
+
+ IN:
+ classname....class name in UTF-8
+ message......the message as an utf *
+
+ RETURN VALUE:
+ an exception pointer (in any case -- either it is the newly created
+ exception, or an exception thrown while trying to create it).
+
+*******************************************************************************/
+
+static java_handle_t *exceptions_new_utf_utf(utf *classname, utf *message)
+{
+ classinfo *c;
+ java_handle_t *o;
+
+ if (vm_initializing)
+ exceptions_abort(classname, message);
+
+ c = load_class_bootstrap(classname);
+
+ if (c == NULL)
+ return exceptions_get_exception();
+
+ o = exceptions_new_class_utf(c, message);
+
+ return o;
+}
+
+
+/* exceptions_throw_class_utf **************************************************
+
+ Creates an exception object with the given class, initalizes and
+ throws it with the given utf message.
+
+ IN:
+ c ......... exception class
+ message ... the message as an utf *
+
+*******************************************************************************/
+
+static void exceptions_throw_class_utf(classinfo *c, utf *message)
+{
+ java_handle_t *o;
+
+ o = exceptions_new_class_utf(c, message);
+
+ exceptions_set_exception(o);
+}
+
+
/* exceptions_throw_utf ********************************************************
Creates an exception object with the given name, initalizes and
}
-/* exceptions_new_utf_javastring ***********************************************
-
- Creates an exception object with the given name and initalizes it
- with the given java/lang/String message.
-
- IN:
- classname....class name in UTF-8
- message......the message as a java.lang.String
-
- RETURN VALUE:
- an exception pointer (in any case -- either it is the newly created
- exception, or an exception thrown while trying to create it).
-
-*******************************************************************************/
-
-static java_handle_t *exceptions_new_utf_javastring(utf *classname,
- java_handle_t *message)
-{
- java_handle_t *o;
- classinfo *c;
-
- if (vm_initializing)
- exceptions_abort(classname, NULL);
-
- c = load_class_bootstrap(classname);
-
- if (c == NULL)
- return exceptions_get_exception();
-
- o = native_new_and_init_string(c, message);
-
- if (o == NULL)
- return exceptions_get_exception();
-
- return o;
-}
-
-
-/* exceptions_new_utf_utf ******************************************************
-
- Creates an exception object with the given name and initalizes it
- with the given utf message.
-
- IN:
- classname....class name in UTF-8
- message......the message as an utf *
-
- RETURN VALUE:
- an exception pointer (in any case -- either it is the newly created
- exception, or an exception thrown while trying to create it).
-
-*******************************************************************************/
-
-static java_handle_t *exceptions_new_utf_utf(utf *classname, utf *message)
-{
- classinfo *c;
- java_handle_t *s;
- java_handle_t *o;
-
- if (vm_initializing)
- exceptions_abort(classname, message);
-
- c = load_class_bootstrap(classname);
-
- if (c == NULL)
- return exceptions_get_exception();
-
- s = javastring_new(message);
-
- if (s == NULL)
- return exceptions_get_exception();
-
- o = native_new_and_init_string(c, s);
-
- if (o == NULL)
- return exceptions_get_exception();
-
- return o;
-}
-
-
/* exceptions_throw_utf_utf ****************************************************
Creates an exception object with the given name, initalizes and
java_object_t *exceptions_asm_new_abstractmethoderror(u1 *sp, u1 *ra)
{
- stackframeinfo sfi;
- java_handle_t *e;
- java_object_t *o;
+ stackframeinfo_t sfi;
+ java_handle_t *e;
+ java_object_t *o;
/* Fill and add a stackframeinfo (XPC is equal to RA). */
void exceptions_throw_classnotfoundexception(utf *name)
{
- exceptions_throw_utf_utf(utf_java_lang_ClassNotFoundException, name);
+ exceptions_throw_class_utf(class_java_lang_ClassNotFoundException, name);
}
}
-/* exceptions_classnotfoundexception_to_noclassdeffounderror *******************
-
- Check the exception for a ClassNotFoundException. If it is one,
- convert it to a NoClassDefFoundError.
-
-*******************************************************************************/
-
-void exceptions_classnotfoundexception_to_noclassdeffounderror(void)
-{
- classinfo *c;
- java_handle_t *o;
- java_handle_t *cause;
- java_lang_Throwable *object;
- java_lang_String *s;
-
- /* Load java/lang/ClassNotFoundException for the instanceof
- check. */
-
- c = load_class_bootstrap(utf_java_lang_ClassNotFoundException);
-
- if (c == NULL)
- return;
-
- /* Get the cause. */
-
- cause = exceptions_get_exception();
-
- /* Convert ClassNotFoundException's to NoClassDefFoundError's. */
-
- if (builtin_instanceof(cause, c)) {
- /* clear exception, because we are calling jit code again */
-
- exceptions_clear_exception();
-
- /* create new error */
-
- object = (java_lang_Throwable *) cause;
- LLNI_field_get_ref(object, detailMessage, s);
-
- o = exceptions_new_utf_javastring(utf_java_lang_NoClassDefFoundError,
- (java_handle_t *) s);
-
- /* we had an exception while creating the error */
-
- if (exceptions_get_exception())
- return;
-
- /* set new exception */
-
- exceptions_set_exception(o);
- }
-}
-
-
/* exceptions_fillinstacktrace *************************************************
Calls the fillInStackTrace-method of the currently thrown
*******************************************************************************/
#if defined(ENABLE_JIT)
-u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp)
+void *exceptions_handle_exception(java_object_t *xptro, void *xpc, void *pv, void *sp)
{
- stackframeinfo sfi;
- java_handle_t *xptr;
- methodinfo *m;
- codeinfo *code;
- s4 issync;
- dseg_exception_entry *ex;
- s4 exceptiontablelength;
- s4 i;
- classref_or_classinfo cr;
- classinfo *c;
+ stackframeinfo_t sfi;
+ java_handle_t *xptr;
+ methodinfo *m;
+ codeinfo *code;
+ exceptiontable_t *et;
+ exceptiontable_entry_t *ete;
+ s4 i;
+ classref_or_classinfo cr;
+ classinfo *c;
#if defined(ENABLE_THREADS)
- java_object_t *o;
+ java_object_t *o;
#endif
- u1 *result;
+ void *result;
#ifdef __S390__
/* Addresses are 31 bit integers */
-# define ADDR_MASK(x) (u1 *)((u4)(x) & 0x7FFFFFFF)
+# define ADDR_MASK(x) (void *) ((uintptr_t) (x) & 0x7FFFFFFF)
#else
# define ADDR_MASK(x) (x)
#endif
result = NULL;
- /* get info from the method header */
+ /* Get the codeinfo for the current method. */
- code = *((codeinfo **) (pv + CodeinfoPointer));
- issync = *((s4 *) (pv + IsSync));
- ex = (dseg_exception_entry *) (pv + ExTableStart);
- exceptiontablelength = *((s4 *) (pv + ExTableSize));
+ code = code_get_codeinfo_for_pv(pv);
/* Get the methodinfo pointer from the codeinfo pointer. For
- asm_vm_call_method the codeinfo pointer is NULL. */
+ asm_vm_call_method the codeinfo pointer is NULL and we simply
+ can return the proper exception handler. */
- m = (code == NULL) ? NULL : code->m;
+ if (code == NULL) {
+ result = (void *) (uintptr_t) &asm_vm_call_method_exception_handler;
+ goto exceptions_handle_exception_return;
+ }
+
+ m = code->m;
#if !defined(NDEBUG)
/* print exception trace */
# endif
#endif
- for (i = 0; i < exceptiontablelength; i++) {
- /* ATTENTION: keep this here, as we need to decrement the
- pointer before the loop executes! */
+ /* Get the exception table. */
- ex--;
+ et = code->exceptiontable;
- /* If the start and end PC is NULL, this means we have the
- special case of asm_vm_call_method. So, just return the
- proper exception handler. */
+ if (et != NULL) {
+ /* Iterate over all exception table entries. */
- if ((ex->startpc == NULL) && (ex->endpc == NULL)) {
- result = (u1 *) (ptrint) &asm_vm_call_method_exception_handler;
- goto exceptions_handle_exception_return;
- }
+ ete = et->entries;
+ for (i = 0; i < et->length; i++, ete++) {
/* is the xpc is the current catch range */
- if ((ADDR_MASK(ex->startpc) <= xpc) && (xpc < ADDR_MASK(ex->endpc))) {
- cr = ex->catchtype;
+ if ((ADDR_MASK(ete->startpc) <= xpc) && (xpc < ADDR_MASK(ete->endpc))) {
+ cr = ete->catchtype;
/* NULL catches everything */
if (opt_TraceExceptions) {
exceptions_print_exception(xptr);
- stacktrace_print_trace(xptr);
+ stacktrace_print_exception(xptr);
}
#endif
- result = ex->handlerpc;
+ result = ete->handlerpc;
goto exceptions_handle_exception_return;
}
if (IS_CLASSREF(cr)) {
/* The exception class reference is unresolved. */
- /* We have to do _eager_ resolving here. While the class of */
- /* the exception object is guaranteed to be loaded, it may */
- /* well have been loaded by a different loader than the */
- /* defining loader of m's class, which is the one we must */
- /* use to resolve the catch class. Thus lazy resolving */
- /* might fail, even if the result of the resolution would */
- /* be an already loaded class. */
+ /* We have to do _eager_ resolving here. While the
+ class of the exception object is guaranteed to be
+ loaded, it may well have been loaded by a different
+ loader than the defining loader of m's class, which
+ is the one we must use to resolve the catch
+ class. Thus lazy resolving might fail, even if the
+ result of the resolution would be an already loaded
+ class. */
c = resolve_classref_eager(cr.ref);
goto exceptions_handle_exception_return;
}
- /* Ok, we resolved it. Enter it in the table, so we don't */
- /* have to do this again. */
- /* XXX this write should be atomic. Is it? */
+ /* Ok, we resolved it. Enter it in the table, so we
+ don't have to do this again. */
+ /* XXX this write should be atomic. Is it? */
- ex->catchtype.cls = c;
- } else {
+ ete->catchtype.cls = c;
+ }
+ else {
c = cr.cls;
/* XXX I don't think this case can ever happen. -Edwin */
m->class->classloader))
goto exceptions_handle_exception_return;
- /* XXX I think, if it is not linked, we can be sure that */
- /* the exception object is no (indirect) instance of it, no? */
- /* -Edwin */
+ /* XXX I think, if it is not linked, we can be sure
+ that the exception object is no (indirect) instance
+ of it, no? -Edwin */
if (!(c->state & CLASS_LINKED))
if (!link_class(c))
goto exceptions_handle_exception_return;
if (opt_TraceExceptions) {
exceptions_print_exception(xptr);
- stacktrace_print_trace(xptr);
+ stacktrace_print_exception(xptr);
}
#endif
- result = ex->handlerpc;
+ result = ete->handlerpc;
goto exceptions_handle_exception_return;
}
}
}
+ }
#if defined(ENABLE_THREADS)
- /* is this method synchronized? */
+ /* Is this method realization synchronized? */
- if (issync) {
- /* get synchronization object */
+ if (code_is_synchronized(code)) {
+ /* Get synchronization object. */
-# if (defined(__MIPS__) && (SIZEOF_VOID_P == 4)) || defined(__I386__) || defined(__S390__) || defined(__POWERPC__)
- /* XXX change this if we ever want to use 4-byte stackslots */
- o = *((java_object_t **) (sp + issync - 8));
-# else
- o = *((java_object_t **) (sp + issync - SIZEOF_VOID_P));
-# endif
+ o = *((java_object_t **) (((uintptr_t) sp) + code->synchronizedoffset));
assert(o != NULL);
- lock_monitor_exit(o);
+ lock_monitor_exit(LLNI_QUICKWRAP(o));
}
#endif
void exceptions_print_stacktrace(void)
{
- java_handle_t *oxptr;
- java_handle_t *xptr;
- classinfo *c;
- methodinfo *m;
+ java_handle_t *e;
+ java_handle_t *ne;
+ classinfo *c;
+ methodinfo *m;
+
+#if defined(ENABLE_THREADS)
+ threadobject *t;
+ java_lang_Thread *to;
+#endif
+
+ /* Get and clear exception because we are calling Java code
+ again. */
- /* get original exception */
+ e = exceptions_get_and_clear_exception();
- oxptr = exceptions_get_and_clear_exception();
+ if (e == NULL)
+ return;
- if (oxptr == NULL)
- vm_abort("exceptions_print_stacktrace: no exception thrown");
+#if 0
+ /* FIXME Enable me. */
+ if (builtin_instanceof(e, class_java_lang_ThreadDeath)) {
+ /* Don't print anything if we are being killed. */
+ }
+ else
+#endif
+ {
+ /* Get the exception class. */
- /* clear exception, because we are calling jit code again */
+ LLNI_class_get(e, c);
- LLNI_class_get(oxptr, c);
+ /* Find the printStackTrace() method. */
- /* find the printStackTrace() method */
+ m = class_resolveclassmethod(c,
+ utf_printStackTrace,
+ utf_void__void,
+ class_java_lang_Object,
+ false);
- m = class_resolveclassmethod(c,
- utf_printStackTrace,
- utf_void__void,
- class_java_lang_Object,
- false);
+ if (m == NULL)
+ vm_abort("exceptions_print_stacktrace: printStackTrace()V not found");
- if (m == NULL)
- vm_abort("exceptions_print_stacktrace: printStackTrace()V not found");
+ /* Print message. */
+
+ fprintf(stderr, "Exception ");
+
+#if defined(ENABLE_THREADS)
+ /* Print thread name. We get the thread here explicitly as we
+ need it afterwards. */
- /* print compatibility message */
+ t = thread_get_current();
+ to = (java_lang_Thread *) thread_get_object(t);
- fprintf(stderr, "Exception in thread \"main\" ");
+ if (to != NULL) {
+ fprintf(stderr, "in thread \"");
+ thread_fprint_name(t, stderr);
+ fprintf(stderr, "\" ");
+ }
+#endif
- /* print the stacktrace */
+ /* Print the stacktrace. */
- (void) vm_call_method(m, oxptr);
+ if (builtin_instanceof(e, class_java_lang_Throwable)) {
+ (void) vm_call_method(m, e);
- /* This normally means, we are EXTREMLY out of memory or
- have a serious problem while printStackTrace. But may
- be another exception, so print it. */
+ /* If this happens we are EXTREMLY out of memory or have a
+ serious problem while printStackTrace. But may be
+ another exception, so print it. */
- xptr = exceptions_get_exception();
+ ne = exceptions_get_exception();
- if (xptr != NULL) {
- fprintf(stderr, "Exception while printStackTrace(): ");
+ if (ne != NULL) {
+ fprintf(stderr, "Exception while printStackTrace(): ");
- /* now print original exception */
+ /* Print the current exception. */
- exceptions_print_exception(xptr);
- stacktrace_print_trace(xptr);
+ exceptions_print_exception(ne);
+ stacktrace_print_exception(ne);
- /* now print original exception */
+ /* Now print the original exception. */
- fprintf(stderr, "Original exception was: ");
- exceptions_print_exception(oxptr);
- stacktrace_print_trace(oxptr);
- }
+ fprintf(stderr, "Original exception was: ");
+ exceptions_print_exception(e);
+ stacktrace_print_exception(e);
+ }
+ }
+ else {
+ fprintf(stderr, ". Uncaught exception of type ");
+ /* FIXME This prints to stdout. */
+ class_print(c);
+ fprintf(stderr, ".");
+ }
- fflush(stderr);
+ fflush(stderr);
+ }
}