[kaffe] -O4 jit3 problem

Patrick Tullmann tullmann@cs.utah.edu
Fri, 14 Jun 2002 18:16:45 -0600


Tim wrote:
> I had a little problem 
	...
> in exception.h.  The "assert(start < end);" needs to be changed to
> "assert(start <= end);" otherwise it will fail if there are no
> instructions between the start_label and end_label.  Which seems to
> happen with Kaffe_ExceptionOccurred() and if NEED_JNIREFS isn't
> defined...

Ah, good catch.

I've updated the patch to do per-method native exception handlers to
include Tim's fix, and to hide the GCC-isms behind "#if
defined(__GNUC__)", as Gwenole Beauchesne pointed out.

Note that with this patch, jni.c will *fail to compile* with an
"#error" if its not being compiled with GCC.  Looking at the sources,
there is currently a lot of GCC-specific code (mostly asm's) in Kaffe.
However, all of that stuff is kept off in the config/ tree, so the
core of the VM is actually free of GCC-isms (I think).

Is this a problem if Kaffe requires GCC?  Anyone out there compile
Kaffe with a non-gcc compiler?

Note that the there is still a problem with intern'd strings and dead
value arrays.  (This patch tickles things just right so that InternHog
in the intrp+debug version will fail.)  At this point, I'm quite
confident that that is a separate bug, and that Tim's suggestion to
gcAddRef/gcRemRef on the underlying char array will at least fix the
crashes.  But that will be a separate patch.

Anywhere, here is the latest patch.  And a ChangeLog entry:

Patrick Tullmann <pat@tullmann.org>
	* kaffe/kaffevm/classMethod.c: Compile methodNeedsTrampoline()
	  in JIT only.
	* kaffe/kaffevm/exception.h: Replace VMException struct
	  with VMExceptHandler, add accessors, 
	* kaffe/kaffevm/exception.c: Use new VMExceptHandler struct in
	  place of VMException, update test to see if a JNI handler is
	  installed when dispatching exceptions	  
	* kaffe/kaffevm/intrp/machine.c: Use new VMExceptHandler and
	  accessors
	* kaffe/kaffevm/jni.c: Use label-addresses to provide
	  exception handler coverage for JNI entrypoints.
	* kaffe/kaffevm/kaffe_jni.h: New header JNI entrypoints used
	  elsewhere in kaffevm.	     
	* kaffe/kaffevm/stackTrace.h: Use new VMExceptHandler.
	* kaffe/kaffevm/support.c: Use new VMExceptHandler.

-Pat

----- ----- ---- ---  ---  --   -    -      -         -               -
Pat Tullmann                                       tullmann@cs.utah.edu
 Indifference may cause the downfall of mankind, but who really cares?

diff -u -r -N --exclude=CVS --exclude=.* --exclude=DEAD --exclude=Makefile.in --exclude=configure pure/kaffe/kaffevm/classMethod.c optjit/kaffe/kaffevm/classMethod.c
--- pure/kaffe/kaffevm/classMethod.c	Wed May 29 16:58:43 2002
+++ optjit/kaffe/kaffevm/classMethod.c	Mon Jun  3 20:25:58 2002
@@ -1559,6 +1559,7 @@
 	return true;
 }
 
+#if defined(TRANSLATOR)
 /*
  * When do we need a trampoline?
  *
@@ -1604,6 +1605,9 @@
 	}
 	return (false);
 }
+#endif /* TRANSLATOR */
+
+
 
 /*
  * Build a trampoline if necessary, return the address of the native code
diff -u -r -N --exclude=CVS --exclude=.* --exclude=DEAD --exclude=Makefile.in --exclude=configure pure/kaffe/kaffevm/exception.c optjit/kaffe/kaffevm/exception.c
--- pure/kaffe/kaffevm/exception.c	Wed May 29 13:46:24 2002
+++ optjit/kaffe/kaffevm/exception.c	Mon Jun  3 22:57:20 2002
@@ -37,6 +37,7 @@
 #include "machine.h"
 #include "slots.h"
 #include "gcj/gcj.h"
+#include "kaffe_jni.h"
 
 #if defined(INTERPRETER)
 #define	FIRSTFRAME(f, e)	/* Does nothing */
@@ -48,8 +49,6 @@
 static void floatingException(struct _exceptionFrame *);
 static void dispatchException(Hjava_lang_Throwable*, stackTraceInfo*) __NORETURN__;
 
-extern void Kaffe_JNIExceptionHandler(void);
-
 extern void printStackTrace(struct Hjava_lang_Throwable*, struct Hjava_lang_Object*, int);
 
 static bool findExceptionBlockInMethod(uintp, Hjava_lang_Class*, Method*, exceptionInfo*);
@@ -297,9 +296,9 @@
                 return (0);
         }
 #endif
-#else
-        vmException* nfm;
-        nfm = ((vmException*)fm)->prev;
+#else	/* INTERPRETER */
+        VmExceptHandler* nfm;
+        nfm = ((VmExceptHandler*)fm)->prev;
 	return (nfm);
 #endif
 }
@@ -330,8 +329,22 @@
 
 	meth = findExceptionInMethod(frame->pc, class, &einfo);
 
-	if (einfo.method == 0 && IS_IN_JNI_RANGE(frame->pc)) {
-		Kaffe_JNIExceptionHandler();
+	assert(meth == einfo.method);
+
+	/*
+	 * If no exception block found in method, perhaps
+	 * it is a Kaffe_JNI entrypoint?
+	 */
+	if (einfo.method == 0)
+	{
+		VmExceptHandler* ebuf = (VmExceptHandler*)(unhand(getCurrentThread())->exceptPtr);
+		if ((ebuf != 0)
+		    && vmExcept_isJNIFrame(ebuf)
+		    && vmExcept_JNIContains(ebuf, frame->pc))
+		{
+			/* Does not return. */
+			Kaffe_JNIExceptionHandler(ebuf);
+		}
 	}
 
 	/* Find the sync. object */
@@ -404,18 +417,21 @@
 	{
 		Hjava_lang_Object* obj;
 		exceptionInfo einfo;
-		vmException* frame;
+		VmExceptHandler* frame;
 		bool res;
 
-		for (frame = (vmException*)unhand(ct)->exceptPtr; frame != 0; frame = frame->prev) {
+		for (frame = (VmExceptHandler*)unhand(ct)->exceptPtr; frame != 0; frame = frame->prev) {
 
-			if (frame->meth == (Method*)1) {
+			if (vmExcept_isJNIFrame(frame)) {
 				unhand(ct)->exceptPtr = (struct Hkaffe_util_Ptr*)frame;
-				Kaffe_JNIExceptionHandler();
+				Kaffe_JNIExceptionHandler(frame); /* No Return */
 			}
 
 			/* Look for handler */
-			res = findExceptionBlockInMethod(frame->pc, eobj->base.dtable->class, frame->meth, &einfo);
+			res = findExceptionBlockInMethod(frame->frame.intrp.pc,
+							 eobj->base.dtable->class,
+							 frame->meth,
+							 &einfo);
 
 			/* Find the sync. object */
 			if (einfo.method == 0 || (einfo.method->accflags & ACC_SYNCHRONISED) == 0) {
@@ -425,14 +441,14 @@
 				obj = &einfo.class->head;
 			}
 			else {
-				obj = frame->mobj;
+				obj = vmExcept_getSyncobj(frame);
 			}
 
 			/* If handler found, call it */
 			if (res == true) {
 				unhand(ct)->needOnStack = STACK_HIGH;
-				frame->pc = einfo.handler;
-				JTHREAD_LONGJMP(JTHREAD_ACCESS_JMPBUF(frame, jbuf), 1);
+				vmExcept_setPC(frame, einfo.handler);
+				vmExcept_jumpToHandler(frame); /* Does not return */
 			}
 
 			/* If not here, exit monitor if synchronised. */
@@ -569,6 +585,9 @@
 /*
  * Look for exception block in method.
  * Returns true if there is an exception handler, false otherwise.
+ *
+ * Passed 'pc' is the program counter where the exception entered
+ * the current frame (the 'throw' or from a nested method call).
  */
 static bool
 findExceptionBlockInMethod(uintp pc, Hjava_lang_Class* class, Method* ptr, exceptionInfo* info)
diff -u -r -N --exclude=CVS --exclude=.* --exclude=DEAD --exclude=Makefile.in --exclude=configure pure/kaffe/kaffevm/exception.h optjit/kaffe/kaffevm/exception.h
--- pure/kaffe/kaffevm/exception.h	Wed May 29 13:46:24 2002
+++ optjit/kaffe/kaffevm/exception.h	Mon Jun 10 12:32:44 2002
@@ -13,6 +13,23 @@
 
 #include "config-setjmp.h"
 
+/*
+ * Values for Thread.needOnStack.  This variable
+ * says how many bytes need to be left on the stack when entering a function
+ * call.  When throwing a StackOverflowException, this variable is set to
+ * STACK_LOW to have enough space to create the StackOverflowError --- if
+ * the error is caught, we set it back to STACK_HIGH.
+ */
+#define STACK_HIGH      (8*1024)
+#define STACK_LOW       256
+
+/* XXX Why is this here?  Its duplicated in a number of places. */
+#if defined(__WIN32__)
+#define SIG_T   void(*)()
+#else
+#define SIG_T   void*
+#endif
+
 struct _exceptionFrame;
 struct Hjava_lang_Class;
 struct Hjava_lang_Object;
@@ -36,13 +53,46 @@
 	jexceptionEntry			entry[1];
 } jexception;
 
-typedef struct _vmException {
-	struct _vmException*		prev;
-	JTHREAD_DECLARE_JMPBUF		(jbuf);
+/*
+ * A VmExceptHandle is used to handle *any* exception in native code
+ * in the core of the VM.  Set up when entering Kaffe_JNI methods, or
+ * when callMethodA or callMethodV are invoked.
+ *
+ * Each thread in the system has a exceptPtr, which points
+ * to the most recent VmExceptHandler buffer (the buffers
+ * are chained throught the 'prev' field.)
+ *
+ * In the interpreter *every frame* has a VmExceptHandler
+ * associated with it, this is used for catching exceptions at
+ * each interpreter stack frame and unlocking synchronized
+ * objects if necessary.
+ */
+typedef struct VmExceptHandler {
+	struct VmExceptHandler*		prev;
 	struct _methods*		meth;
-	u4				pc;
-	struct Hjava_lang_Object*	mobj;
-} vmException;
+	union
+	{
+		/* Only valid if meth == VMEXCEPTHANDLER_KAFFEJNI_HANDLER */
+		struct
+		{
+			const void*	start;
+			const void*	end;
+		} jni;
+		/*
+		 * Only valid if meth != 0 && meth != VMEXCEPTHANDLER_KAFFEJNI_HANDLER
+		 *
+		 * XXX Only used in the interpreter...
+		 */
+		struct
+		{
+			struct Hjava_lang_Object*	syncobj;
+			u4				pc;
+		} intrp;
+	} frame;
+	JTHREAD_DECLARE_JMPBUF		(jbuf);
+} VmExceptHandler;
+
+#define VMEXCEPTHANDLER_KAFFEJNI_HANDLER ((struct _methods*)1)
 
 struct _exceptionFrame;
 
@@ -56,26 +106,118 @@
 				  struct Hjava_lang_Throwable *eobj);
 void unhandledException(struct Hjava_lang_Throwable *eobj) __NORETURN__;
 
-extern uintp Kaffe_JNI_estart;
-extern uintp Kaffe_JNI_eend;
-#define	IS_IN_JNI_RANGE(pc) ((pc) >= Kaffe_JNI_estart && (pc) < Kaffe_JNI_eend)
-
 extern void initExceptions(void);
 
-#if defined(__WIN32__)
-#define SIG_T   void(*)()
-#else
-#define SIG_T   void*
+static inline bool vmExcept_isJNIFrame(VmExceptHandler* eh) __UNUSED__;
+static inline bool vmExcept_JNIContains(VmExceptHandler* eh, void *pc) __UNUSED__;
+static inline void vmExcept_setJNIFrame(VmExceptHandler* eh, const void* start, const void* end) __UNUSED__;
+static inline struct _methods* vmExcept_getMeth(VmExceptHandler* eh) __UNUSED__;
+static inline void vmExcept_setMeth(VmExceptHandler* eh, struct _methods* m) __UNUSED__;
+static inline void vmExcept_setSyncobj(VmExceptHandler* eh, struct Hjava_lang_Object* syncobj) __UNUSED__;
+static inline struct Hjava_lang_Object* vmExcept_getSyncobj(VmExceptHandler* eh) __UNUSED__;
+static inline void vmExcept_setPC(volatile VmExceptHandler* eh, u4 pc) __UNUSED__;
+static inline u4 vmExcept_getPC(const VmExceptHandler* eh) __UNUSED__;
+static inline void vmExcept_jumpToHandler(VmExceptHandler* frame) __UNUSED__ __NORETURN__;
+
+static inline bool
+vmExcept_isJNIFrame(VmExceptHandler* eh)
+{
+	assert(eh);
+	return (eh->meth == VMEXCEPTHANDLER_KAFFEJNI_HANDLER);
+}
+
+static inline bool
+vmExcept_JNIContains(VmExceptHandler* eh, void *pc)
+{
+	assert(eh);
+	assert(eh->meth == VMEXCEPTHANDLER_KAFFEJNI_HANDLER);
+	assert(pc);
+	
+	return (eh->frame.jni.start <= pc)
+		&& (eh->frame.jni.end > pc);
+}
+
+static inline void
+vmExcept_jumpToHandler(VmExceptHandler* frame)
+{
+	JTHREAD_LONGJMP(JTHREAD_ACCESS_JMPBUF(frame, jbuf), 1);
+}
+
+static inline void 
+vmExcept_setJNIFrame(VmExceptHandler* eh, const void* start, const void* end)
+{
+	assert(eh);
+	assert(start != 0);
+	assert(start <= end);
+
+	eh->meth = VMEXCEPTHANDLER_KAFFEJNI_HANDLER;
+	eh->frame.jni.start = start;
+	eh->frame.jni.end = end;
+}
+
+static inline void 
+vmExcept_setIntrpFrame(VmExceptHandler* eh, u4 pc, struct _methods* meth, struct Hjava_lang_Object* syncobj)
+{
+	assert(eh);
+	assert(meth);
+	
+	eh->meth = meth;
+	eh->frame.intrp.pc = pc;
+	eh->frame.intrp.syncobj = syncobj;
+}
+
+static inline void 
+vmExcept_setSyncobj(VmExceptHandler* eh, struct Hjava_lang_Object* syncobj)
+{
+	assert(eh);
+	assert(eh->meth != 0);
+	assert(eh->meth != VMEXCEPTHANDLER_KAFFEJNI_HANDLER);
+	eh->frame.intrp.syncobj = syncobj;
+}
+
+static inline struct Hjava_lang_Object*
+vmExcept_getSyncobj(VmExceptHandler* eh)
+{
+	assert(eh);
+	assert(eh->meth != 0);
+	assert(eh->meth != VMEXCEPTHANDLER_KAFFEJNI_HANDLER);
+	return eh->frame.intrp.syncobj;
+}
+
+static inline void 
+vmExcept_setMeth(VmExceptHandler* eh, struct _methods* meth)
+{
+	assert(eh);
+	assert(meth);
+	eh->meth = meth;
+}
+
+static inline struct _methods* 
+vmExcept_getMeth(VmExceptHandler* eh)
+{
+	assert(eh);
+	return eh->meth;
+}
+
+static inline void 
+vmExcept_setPC(volatile VmExceptHandler* eh, u4 pc)
+{
+	assert(eh);
+	assert(eh->meth != 0);
+	assert(eh->meth != VMEXCEPTHANDLER_KAFFEJNI_HANDLER);
+	eh->frame.intrp.pc = pc;
+}
+
+static inline u4 
+vmExcept_getPC(const VmExceptHandler* eh)
+{
+	assert(eh);
+	assert(eh->meth != 0);
+	assert(eh->meth != VMEXCEPTHANDLER_KAFFEJNI_HANDLER);
+	return eh->frame.intrp.pc;
+}
+
 #endif
 
-/*
- * Values for Thread.needOnStack.  This variable
- * says how many bytes need to be left on the stack when entering a function
- * call.  When throwing a StackOverflowException, this variable is set to
- * STACK_LOW to have enough space to create the StackOverflowError --- if
- * the error is caught, we set it back to STACK_HIGH.
- */
-#define STACK_HIGH      (8*1024)
-#define STACK_LOW       256
 
-#endif
+
diff -u -r -N --exclude=CVS --exclude=.* --exclude=DEAD --exclude=Makefile.in --exclude=configure pure/kaffe/kaffevm/intrp/machine.c optjit/kaffe/kaffevm/intrp/machine.c
--- pure/kaffe/kaffevm/intrp/machine.c	Sun Jun 17 10:39:34 2001
+++ optjit/kaffe/kaffevm/intrp/machine.c	Mon Jun  3 21:09:05 2002
@@ -84,14 +84,14 @@
 int profFlag;			 /* flag to control profiling */
 #endif
 
-void runVirtualMachine(methods *meth, slots *lcl, slots *sp, uintp npc, slots *retval, volatile vmException *mjbuf, Hjava_lang_Thread *tid);
+void runVirtualMachine(methods *meth, slots *lcl, slots *sp, uintp npc, slots *retval, volatile VmExceptHandler *mjbuf, Hjava_lang_Thread *tid);
 
 void
 virtualMachine(methods*volatile meth, slots* volatile arg, slots* volatile retval, Hjava_lang_Thread* volatile tid)
 {
 	methods *volatile const vmeth = meth;
 	Hjava_lang_Object* volatile mobj;
-	vmException mjbuf;
+	VmExceptHandler mjbuf;
 	accessFlags methaccflags;
 
 	slots* volatile lcl;
@@ -168,11 +168,9 @@
 	/* If we have any exception handlers we must prepare to catch them.
 	 * We also need to catch if we are synchronised (so we can release it).
 	 */
-	mjbuf.pc = 0;
-	mjbuf.mobj = mobj;
-	mjbuf.meth = meth;
+	vmExcept_setIntrpFrame(&mjbuf, 0, meth, mobj);
 	if (tid != NULL && unhand(tid)->PrivateInfo != 0) {
-		mjbuf.prev = (vmException*)unhand(tid)->exceptPtr;
+		mjbuf.prev = (VmExceptHandler*)unhand(tid)->exceptPtr;
 		unhand(tid)->exceptPtr = (struct Hkaffe_util_Ptr*)&mjbuf;
 	}
 
@@ -180,7 +178,7 @@
 		if (JTHREAD_SETJMP(mjbuf.jbuf) != 0) {
 			meth = vmeth;
 			unhand(tid)->exceptPtr = (struct Hkaffe_util_Ptr*)&mjbuf;
-			npc = mjbuf.pc;
+			npc = vmExcept_getPC(&mjbuf);
 			sp = &lcl[meth->localsz];
 #if defined(DEBUG)
 			{
@@ -219,11 +217,13 @@
 		}
 		/* this lock is safe for Thread.stop() */
 		lockObject(mobj);
-		/* We must store the object on which we synchronized in
-		 * the mjbuf chain or else the exception handler routine
-		 * won't find it.
+
+		/*
+		 * We must store the object on which we synchronized
+		 * in the mjbuf chain for the exception handler
+		 * routine to find it (and unlock it when unwinding).
 		 */
-		mjbuf.mobj = mobj;
+		vmExcept_setSyncobj(&mjbuf, mobj);
 	}
 
 	sp = &lcl[meth->localsz - 1];
@@ -242,7 +242,7 @@
 RDBG(	dprintf("Returning from method %s%s.\n", meth->name->data, METHOD_SIGD(meth)); )
 }
 
-void runVirtualMachine(methods *meth, slots *lcl, slots *sp, uintp npc, slots *retval, volatile vmException *mjbuf, Hjava_lang_Thread *tid) {
+void runVirtualMachine(methods *meth, slots *lcl, slots *sp, uintp npc, slots *retval, volatile VmExceptHandler *mjbuf, Hjava_lang_Thread *tid) {
 	bytecode *code = (bytecode*)meth->c.bcode.code;
 
 	/* Misc machine variables */
@@ -268,7 +268,7 @@
 		register uintp pc = npc;
 
 		assert(npc < meth->c.bcode.codelen);
-		mjbuf->pc = pc;
+		vmExcept_setPC(mjbuf, pc);
 		npc = pc + insnLen[code[pc]];
 
 		switch (code[pc]) {
diff -u -r -N --exclude=CVS --exclude=.* --exclude=DEAD --exclude=Makefile.in --exclude=configure pure/kaffe/kaffevm/jni.c optjit/kaffe/kaffevm/jni.c
--- pure/kaffe/kaffevm/jni.c	Wed May 29 16:58:44 2002
+++ optjit/kaffe/kaffevm/jni.c	Tue Jun  4 03:04:53 2002
@@ -47,6 +47,7 @@
 #include "machine.h"
 #include "feedback.h"
 #endif
+#include "kaffe_jni.h"
 
 /*
  * Define the version of JNI we support.
@@ -80,34 +81,50 @@
  */
 #define	JNI_METHOD_CODE(M)	METHOD_INDIRECTMETHOD(M)
 
+#if defined(__GNUC__)
+/*
+ * Yes, that's a unary "&&" to get the address of a label.  See:
+ * http://gcc.gnu.org/onlinedocs/gcc/Local-Labels.html#Local%20Labels
+ * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html#Labels%20as%20Values
+ */
+#define LABEL_ADDR(x) (&&x)
+#else
+#error LABEL_ADDR Taking the address of a label is a GCC-extension to C
+#endif
+
 /*
  * Define how we handle exceptions in JNI.
  *
- * XXX variable declarations in macros are nasty.
+ * Each BEGIN_EXCEPTION_HANDLING macro must be matched by an
+ * END_EXCEPTION_HANDLING macro call in the same scope.  Each should
+ * be used only once in a given JNI entrypoint.
  */
 #define	BEGIN_EXCEPTION_HANDLING(X)			\
-	vmException ebuf;				\
-	ebuf.prev = (vmException*)unhand(getCurrentThread())->exceptPtr;\
-	ebuf.meth = (Method*)1;				\
-	if (JTHREAD_SETJMP(ebuf.jbuf) != 0) {		\
+	VmExceptHandler ebuf;				\
+	vmExcept_setJNIFrame(&ebuf, LABEL_ADDR(start_label), LABEL_ADDR(end_label)); \
+	ebuf.prev = (VmExceptHandler*)(unhand(getCurrentThread())->exceptPtr);\
+	if (JTHREAD_SETJMP(JTHREAD_ACCESS_JMPBUF(&ebuf, jbuf)) != 0) {		\
 		unhand(getCurrentThread())->exceptPtr = \
 		  (struct Hkaffe_util_Ptr*)ebuf.prev;	\
 		return X;				\
 	}						\
+    start_label: \
 	unhand(getCurrentThread())->exceptPtr = (struct Hkaffe_util_Ptr*)&ebuf
 
 #define	BEGIN_EXCEPTION_HANDLING_VOID()			\
-	vmException ebuf;				\
-	ebuf.prev = (vmException*)unhand(getCurrentThread())->exceptPtr;\
-	ebuf.meth = (Method*)1;				\
-	if (JTHREAD_SETJMP(ebuf.jbuf) != 0) {		\
+	VmExceptHandler ebuf;				\
+	vmExcept_setJNIFrame(&ebuf, LABEL_ADDR(start_label), LABEL_ADDR(end_label)); \
+	ebuf.prev = (VmExceptHandler*)(unhand(getCurrentThread())->exceptPtr);\
+	if (JTHREAD_SETJMP(JTHREAD_ACCESS_JMPBUF(&ebuf, jbuf)) != 0) {		\
 		unhand(getCurrentThread())->exceptPtr = \
 		  (struct Hkaffe_util_Ptr*)ebuf.prev;	\
 		return;					\
 	}						\
+    start_label: \
 	unhand(getCurrentThread())->exceptPtr = (struct Hkaffe_util_Ptr*)&ebuf
 
 #define	END_EXCEPTION_HANDLING()			\
+    end_label: \
 	unhand(getCurrentThread())->exceptPtr = (struct Hkaffe_util_Ptr*)ebuf.prev
 
 /*
@@ -118,9 +135,6 @@
 #define	GET_STATIC_FIELD(T,F)	*(T*)FIELD_ADDRESS((Field*)F)
 #define	SET_STATIC_FIELD(T,F,V)	*(T*)FIELD_ADDRESS((Field*)F) = (V)
 
-uintp Kaffe_JNI_estart;
-uintp Kaffe_JNI_eend;
-
 extern struct JNINativeInterface Kaffe_JNINativeInterface;
 extern JavaVMInitArgs Kaffe_JavaVMInitArgs;
 extern JavaVM Kaffe_JavaVM;
@@ -133,7 +147,6 @@
 static void Kaffe_wrapper(Method* xmeth, void* func, bool use_JNI);
 #endif
 
-void Kaffe_JNIExceptionHandler(void);
 static jint Kaffe_GetVersion(JNIEnv*);
 static jclass Kaffe_FindClass(JNIEnv*, const char*);
 static jint Kaffe_ThrowNew(JNIEnv*, jclass, const char*);
@@ -166,10 +179,6 @@
 	Kaffe_JavaVMArgs[0] = *args;
 	initialiseKaffe();
 
-	/* Setup the JNI Exception handler */
-	Kaffe_JNI_estart = (uintp)&Kaffe_GetVersion; /* First routine */
-	Kaffe_JNI_eend = (uintp)&Kaffe_JNIExceptionHandler; /* Last routine */
-
 	/* Setup JNI for main thread */
 #if defined(NEED_JNIREFS)
 	unhand(getCurrentThread())->jnireferences = gc_malloc(sizeof(jnirefs), &gcNormal);
@@ -198,8 +207,6 @@
  *
  * Everything from Kaffe_GetVersion to Kaffe_JNIExceptionHandler
  * should be bracketed with BEGIN and END _EXCEPTION_HANDLING.
- * Question: what happens when an asynchronous exception occurs at the
- * very start or end of one of these calls.
  */
 static void
 Kaffe_FatalError(JNIEnv* env, const char* mess)
@@ -3493,18 +3500,10 @@
  * Handle exceptions which fall back to the JNI layer.
  */
 void
-Kaffe_JNIExceptionHandler(void)
+Kaffe_JNIExceptionHandler(VmExceptHandler* frame)
 {
-	vmException* frame;
-
-	frame = (vmException*)unhand(getCurrentThread())->exceptPtr;
-	if (frame) {
-		/* Worry about window around BEGIN and END exception
-		 * handling, as well as functions which only delay
-		 * external exceptions.
-		 */
-		JTHREAD_LONGJMP(JTHREAD_ACCESS_JMPBUF(frame, jbuf), 1);
-	}
+	assert(frame != 0);
+	vmExcept_jumpToHandler(frame);
 }
 
 /*
diff -u -r -N --exclude=CVS --exclude=.* --exclude=DEAD --exclude=Makefile.in --exclude=configure pure/kaffe/kaffevm/kaffe_jni.h optjit/kaffe/kaffevm/kaffe_jni.h
--- pure/kaffe/kaffevm/kaffe_jni.h	Wed Dec 31 17:00:00 1969
+++ optjit/kaffe/kaffevm/kaffe_jni.h	Mon Jun  3 20:44:20 2002
@@ -0,0 +1,21 @@
+/*
+ * kaffe_jni.h
+ * Prototypes for jni.c methods used elsewhere
+ *
+ * Copyright (c) 2002
+ *	Pat Tullmann <pat@tullmann.org>.  All rights reserved.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file.
+ */
+
+#ifndef KAFFE_KAFFEVM_KAFFE_JNI_H
+#define KAFFE_KAFFEVM_KAFFE_JNI_H
+
+#include "config.h"
+
+struct VmExceptHandler; /* exception.h */
+
+extern void Kaffe_JNIExceptionHandler(struct VmExceptHandler* handler) __NORETURN__;
+
+#endif /* KAFFE_KAFFEVM_KAFFE_JNI_H */
diff -u -r -N --exclude=CVS --exclude=.* --exclude=DEAD --exclude=Makefile.in --exclude=configure pure/kaffe/kaffevm/stackTrace.h optjit/kaffe/kaffevm/stackTrace.h
--- pure/kaffe/kaffevm/stackTrace.h	Fri Jun 16 11:47:13 2000
+++ optjit/kaffe/kaffevm/stackTrace.h	Mon Jun  3 22:46:48 2002
@@ -26,7 +26,7 @@
 #if defined(INTERPRETER)
 
 typedef struct _stackTrace {
-	vmException* frame;
+	VmExceptHandler* frame;
 } stackTrace;
 
 /* Dummy exceptionFrame */
@@ -34,13 +34,13 @@
 	char	dummy;
 };
 
-#define STACKTRACEINIT(S,I,O,R)	((S).frame = (vmException*)unhand(getCurrentThread())->exceptPtr)
+#define STACKTRACEINIT(S,I,O,R)	((S).frame = (VmExceptHandler*)unhand(getCurrentThread())->exceptPtr)
 #define	STACKTRACESTEP(S)	((S).frame = nextFrame((S).frame))
-#define STACKTRACEPC(S)		((S).frame->pc)
+#define STACKTRACEPC(S)		(vmExcept_getPC((S).frame))
 #define STACKTRACEFP(S)		(0)
-#define STACKTRACEMETHCREATE(S)	((S).frame->meth)
+#define STACKTRACEMETHCREATE(S)	(vmExcept_getMeth((S).frame))
 #define STACKTRACEEND(S)	((S).frame == 0)
-#define STACKTRACESKIP(S)	((S).frame->meth == (Method*)1)
+#define STACKTRACESKIP(S)	(vmExcept_isJNIFrame((S).frame))
 
 #elif defined(TRANSLATOR)
 
diff -u -r -N --exclude=CVS --exclude=.* --exclude=DEAD --exclude=Makefile.in --exclude=configure pure/kaffe/kaffevm/support.c optjit/kaffe/kaffevm/support.c
--- pure/kaffe/kaffevm/support.c	Wed May 29 16:58:44 2002
+++ optjit/kaffe/kaffevm/support.c	Mon Jun  3 21:07:17 2002
@@ -529,7 +529,7 @@
 	}
 	else {
 		Hjava_lang_Object* syncobj = 0;
-		vmException mjbuf;
+		VmExceptHandler mjbuf;
 		Hjava_lang_Thread* tid = getCurrentThread();
 
 		if (meth->accflags & ACC_SYNCHRONISED) {
@@ -542,11 +542,9 @@
 			lockObject(syncobj);
 		}
 
-		mjbuf.pc = 0;
-		mjbuf.mobj = syncobj;
-		mjbuf.meth = meth;
+		vmExcept_setIntrpFrame(&mjbuf, 0, meth, syncobj);
 		if (tid != NULL && unhand(tid)->PrivateInfo != 0) {
-			mjbuf.prev = (vmException*)unhand(tid)->exceptPtr;
+			mjbuf.prev = (VmExceptHandler*)unhand(tid)->exceptPtr;
 			unhand(tid)->exceptPtr = (struct Hkaffe_util_Ptr*)&mjbuf;
 		}
 
@@ -747,7 +745,7 @@
 	}
 	else {
 		Hjava_lang_Object* syncobj = 0;
-		vmException mjbuf;
+		VmExceptHandler mjbuf;
 		Hjava_lang_Thread* tid = getCurrentThread();
 
 		if (meth->accflags & ACC_SYNCHRONISED) {
@@ -760,11 +758,9 @@
 			lockObject(syncobj);
 		}
 
-		mjbuf.pc = 0;
-		mjbuf.mobj = syncobj;
-		mjbuf.meth = meth;
+		vmExcept_setIntrpFrame(&mjbuf, 0, meth, syncobj);
 		if (tid != NULL && unhand(tid)->PrivateInfo != 0) {
-			mjbuf.prev = (vmException*)unhand(tid)->exceptPtr;
+			mjbuf.prev = (VmExceptHandler*)unhand(tid)->exceptPtr;
 			unhand(tid)->exceptPtr = (struct Hkaffe_util_Ptr*)&mjbuf;
 		}