+/* exceptions_throw_stringindexoutofboundsexception ****************************
+
+ Throws a java.lang.StringIndexOutOfBoundsException for the VM
+ system.
+
+*******************************************************************************/
+
+void exceptions_throw_stringindexoutofboundsexception(void)
+{
+ *exceptionptr = exceptions_new_stringindexoutofboundsexception();
+}
+
+
+/* exceptions_get_and_clear_exception ******************************************
+
+ Gets the exception pointer of the current thread and clears it.
+ This function may return NULL.
+
+*******************************************************************************/
+
+java_objectheader *exceptions_get_and_clear_exception(void)
+{
+ java_objectheader **p;
+ java_objectheader *e;
+
+ /* get the pointer of the exception pointer */
+
+ p = exceptionptr;
+
+ /* get the exception */
+
+ e = *p;
+
+ /* and clear the exception */
+
+ *p = NULL;
+
+ /* return the exception */
+
+ return e;
+}
+
+
+/* exceptions_handle_exception *************************************************
+
+ Try to find an exception handler for the given exception and return it.
+ If no handler is found, exit the monitor of the method (if any)
+ and return NULL.
+
+ IN:
+ xptr.........the exception object
+ xpc..........PC of where the exception was thrown
+ pv...........Procedure Value of the current method
+ sp...........current stack pointer
+
+ RETURN VALUE:
+ the address of the first matching exception handler, or
+ NULL if no handler was found
+
+*******************************************************************************/
+
+#if defined(ENABLE_JIT)
+u1 *exceptions_handle_exception(java_objectheader *xptr, u1 *xpc, u1 *pv, u1 *sp)
+{
+ methodinfo *m;
+ codeinfo *code;
+ s4 issync;
+ dseg_exception_entry *ex;
+ s4 exceptiontablelength;
+ s4 i;
+ classref_or_classinfo cr;
+ classinfo *c;
+#if defined(ENABLE_THREADS)
+ java_objectheader *o;
+#endif
+
+ /* get info from the method header */
+
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+ issync = *((s4 *) (pv + IsSync));
+ ex = (dseg_exception_entry *) (pv + ExTableStart);
+ exceptiontablelength = *((s4 *) (pv + ExTableSize));
+
+ /* Get the methodinfo pointer from the codeinfo pointer. For
+ asm_vm_call_method the codeinfo pointer is NULL. */
+
+ m = (code == NULL) ? NULL : code->m;
+
+#if !defined(NDEBUG)
+ /* print exception trace */
+
+ if (opt_verbose || opt_verbosecall || opt_verboseexception)
+ builtin_trace_exception(xptr, m, xpc, 1);
+#endif
+
+ for (i = 0; i < exceptiontablelength; i++) {
+ /* ATTENTION: keep this here, as we need to decrement the
+ pointer before the loop executes! */
+
+ ex--;
+
+ /* 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 ((ex->startpc == NULL) && (ex->endpc == NULL))
+ return (u1 *) (ptrint) &asm_vm_call_method_exception_handler;
+
+ /* is the xpc is the current catch range */
+
+ if ((ex->startpc <= xpc) && (xpc < ex->endpc)) {
+ cr = ex->catchtype;
+
+ /* NULL catches everything */
+
+ if (cr.any == NULL) {
+#if !defined(NDEBUG)
+ /* Print stacktrace of exception when caught. */
+
+ if (opt_verboseexception) {
+ exceptions_print_exception(xptr);
+ stacktrace_print_trace(xptr);
+ }
+#endif
+
+ return ex->handlerpc;
+ }
+
+ /* resolve or load/link the exception class */
+
+ 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. */
+
+ c = resolve_classref_eager(cr.ref);
+
+ if (c == NULL) {
+ /* Exception resolving the exception class, argh! */
+ return NULL;
+ }
+
+ /* 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 {
+ c = cr.cls;
+
+ /* XXX I don't think this case can ever happen. -Edwin */
+ if (!(c->state & CLASS_LOADED))
+ /* use the methods' classloader */
+ if (!load_class_from_classloader(c->name,
+ m->class->classloader))
+ return NULL;
+
+ /* 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))
+ return NULL;
+ }
+
+ /* is the thrown exception an instance of the catch class? */
+
+ if (builtin_instanceof(xptr, c)) {
+#if !defined(NDEBUG)
+ /* Print stacktrace of exception when caught. */
+
+ if (opt_verboseexception) {
+ exceptions_print_exception(xptr);
+ stacktrace_print_trace(xptr);
+ }
+#endif
+
+ return ex->handlerpc;
+ }
+ }
+ }
+
+#if defined(ENABLE_THREADS)
+ /* is this method synchronized? */
+
+ if (issync) {
+ /* get synchronization object */
+
+# if defined(__MIPS__) && (SIZEOF_VOID_P == 4)
+ /* XXX change this if we ever want to use 4-byte stackslots */
+ o = *((java_objectheader **) (sp + issync - 8));
+# else
+ o = *((java_objectheader **) (sp + issync - SIZEOF_VOID_P));
+#endif
+
+ assert(o != NULL);
+
+ lock_monitor_exit(o);
+ }
+#endif
+
+ /* none of the exceptions catch this one */
+
+ return NULL;
+}
+#endif /* defined(ENABLE_JIT) */
+
+
+/* exceptions_print_exception **************************************************
+
+ Prints an exception, the detail message and the cause, if
+ available, with CACAO internal functions to stdout.
+
+*******************************************************************************/
+
+void exceptions_print_exception(java_objectheader *xptr)
+{
+ java_lang_Throwable *t;
+ java_lang_Throwable *cause;
+ utf *u;
+
+ t = (java_lang_Throwable *) xptr;
+
+ if (t == NULL) {
+ puts("NULL\n");
+ return;
+ }
+
+ cause = t->cause;
+
+ /* print the root exception */
+
+ utf_display_printable_ascii_classname(t->header.vftbl->class->name);
+
+ if (t->detailMessage) {
+ u = javastring_toutf(t->detailMessage, false);
+
+ printf(": ");
+ utf_display_printable_ascii(u);
+ }
+
+ putc('\n', stdout);
+
+ /* print the cause if available */
+
+ if ((cause != NULL) && (cause != t)) {
+ printf("Caused by: ");
+ utf_display_printable_ascii_classname(cause->header.vftbl->class->name);
+
+ if (cause->detailMessage) {
+ u = javastring_toutf(cause->detailMessage, false);
+
+ printf(": ");
+ utf_display_printable_ascii(u);
+ }
+
+ putc('\n', stdout);
+ }
+}
+
+