⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exception.c

📁 kaffe Java 解释器语言,源码,Java的子集系统,开放源代码
💻 C
字号:
/* * exception.c * Handle exceptions for the interpreter or translator. * * Copyright (c) 1996, 1997 *	Transvirtual Technologies, Inc.  All rights reserved. * Copyright (c) 2003 * 	Mark J. Wielaard <mark@klomp.org> * Copyright (c) 2004 *      Kaffe.org contributors. See ChangeLogs for details. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. */#if defined(HAVE_STDARG_H)#include <stdarg.h>#endif /* defined(HAVE_STDARG_H) */#include <stdio.h>#include "config.h"#include "debug.h"#include "config-std.h"#include "config-signal.h"#include "config-mem.h"#include "config-setjmp.h"#include "config-hacks.h"#include "kaffe/jtypes.h"#include "gtypes.h"#include "access.h"#include "object.h"#include "constants.h"#include "md.h"#include "callKaffeException.h"#include "classMethod.h"#include "code.h"#include "exception.h"#include "baseClasses.h"#include "lookup.h"#include "thread.h"#include "thread-impl.h"#include "errors.h"#include "itypes.h"#include "external.h"#include "soft.h"#include "locks.h"#include "stackTrace.h"#include "machine.h"#include "slots.h"#include "gcj/gcj.h"#include "java_lang_Throwable.h"#include "java_lang_VMThrowable.h"#if defined(INTERPRETER)#define FRAMEOBJECT(O, F, E)    (O) = vmExcept_getSyncObj((VmExceptHandler*)(F))#define DISPATCH_EXCEPTION(F, H, E) vmExcept_setPC((VmExceptHandler *)(F), (H));  \                                    vmExcept_jumpToHandler((VmExceptHandler *)(F)); /* Does not return */#else#define DISPATCH_EXCEPTION(F,H,E) thread_data->exceptObj = 0;\                                  CALL_KAFFE_EXCEPTION((F),(H),(E));#endif	/* TRANSLATOR */static void nullException(struct _exceptionFrame *);static void floatingException(struct _exceptionFrame *);static void dispatchException(Hjava_lang_Throwable*, stackTraceInfo*) __NORETURN__;extern void printStackTrace(struct Hjava_lang_Throwable*, struct Hjava_lang_Object*, int);static bool findExceptionBlockInMethod(uintp, Hjava_lang_Class*, Method*, uintp*);/* * Create an exception from error information. */Hjava_lang_Throwable*error2Throwable(errorInfo* einfo){	Hjava_lang_Throwable *err = 0;	switch (einfo->type & KERR_CODE_MASK) {	case KERR_EXCEPTION:		if (einfo->mess == 0 || *einfo->mess == '\0') {			err = (Hjava_lang_Throwable*)execute_java_constructor(				    einfo->classname, 0, 0, "()V");		} else {			err = (Hjava_lang_Throwable*)execute_java_constructor(				    einfo->classname,				    0, 0, "(Ljava/lang/String;)V",				    checkPtr(stringC2Java(einfo->mess)));		}		break;	case KERR_INITIALIZER_ERROR:		if (strcmp(CLASS_CNAME(OBJECT_CLASS(&einfo->throwable->base)),			   "java/lang/ExceptionInInitializerError") != 0) {			err = (Hjava_lang_Throwable*)execute_java_constructor(				    JAVA_LANG(ExceptionInInitializerError),				    0, 0, "(Ljava/lang/Throwable;)V",				    einfo->throwable);			break;		}		/* FALLTHRU */	case KERR_RETHROW:		err = einfo->throwable;		break;	case KERR_OUT_OF_MEMORY:		err = gc_throwOOM();		break;	}	discardErrorInfo(einfo);	return (err);}/* * post out-of-memory condition */voidpostOutOfMemory(errorInfo *einfo){	memset(einfo, 0, sizeof(*einfo));    	einfo->type = KERR_OUT_OF_MEMORY;}/* * post a simple exception using its full name without a message */voidpostException(errorInfo *einfo, const char *name){	einfo->type = KERR_EXCEPTION;	einfo->classname = name;	einfo->mess = "";	einfo->throwable = 0;}voidvpostExceptionMessage(errorInfo *einfo,	const char * fullname, const char * fmt, va_list args){        char *msgBuf;        int msgLen;	msgBuf = KMALLOC(MAX_ERROR_MESSAGE_SIZE);	if (msgBuf == 0) {		einfo->type = KERR_OUT_OF_MEMORY;		return;	}#ifdef HAVE_VSNPRINTF        msgLen = vsnprintf(msgBuf, MAX_ERROR_MESSAGE_SIZE, fmt, args);#else        /* XXX potential buffer overruns problem: */        msgLen = vsprintf(msgBuf, fmt, args);#endif	einfo->type = KERR_EXCEPTION | KERR_FREE_MESSAGE;	einfo->classname = fullname;	einfo->mess = msgBuf;	einfo->throwable = 0;}/* * post a longer exception with a message using full name */voidpostExceptionMessage(errorInfo *einfo,	const char * fullname, const char * fmt, ...){        va_list args;        va_start(args, fmt);	vpostExceptionMessage(einfo, fullname, fmt, args);        va_end(args);}/* * post a NoClassDefFoundError - we handle this specially since it might * not be a fatal error (depending no where it's generated). */voidpostNoClassDefFoundError(errorInfo* einfo, const char* cname){	postExceptionMessage(einfo, JAVA_LANG(NoClassDefFoundError), "%s", cname);	einfo->type |= KERR_NO_CLASS_FOUND;}/* * Check whether we threw a NoClassFoundError and if we did clear it. * We need this in code-analyse.c to avoid throwing errors when we can't find * classes but to terminate when we get real errors. */intcheckNoClassDefFoundError(errorInfo* einfo){	if (einfo->type & KERR_NO_CLASS_FOUND) {		discardErrorInfo(einfo);		return (1);	}	else {		return (0);	}}/* * dump error info to stderr */voiddumpErrorInfo(errorInfo *einfo){	/* XXX */}/* * discard the errorinfo, freeing a message if necessary */voiddiscardErrorInfo(errorInfo *einfo){	if (einfo->type & KERR_FREE_MESSAGE) {		KFREE(einfo->mess);		einfo->type &= ~KERR_FREE_MESSAGE;	}}/* * Create and throw an exception resulting from an error during VM processing. */voidthrowError(errorInfo* einfo){	Hjava_lang_Throwable* eobj = error2Throwable (einfo);	throwException(eobj);}/* * Throw an exception with backtrace recomputed. * * Semantic: take stacktrace right now (overwrite whatever stacktrace * is in the exception object) and dispatch. */voidthrowException(Hjava_lang_Throwable* eobj){	Hjava_lang_VMThrowable* vmstate;	Hjava_lang_Object* backtrace;	if (eobj == 0) {		dprintf("Exception thrown on null object ... aborting\n");		ABORT();		EXIT(1);	}	vmstate = unhand(eobj)->vmState;	if (vmstate == 0) {		vmstate =		  (Hjava_lang_VMThrowable*)newObject(javaLangVMThrowable);		unhand(eobj)->vmState = vmstate;	}	backtrace = buildStackTrace(0);	unhand(vmstate)->backtrace = backtrace;	dispatchException(eobj, (stackTraceInfo*)backtrace);}/* * Throw an exception without altering backtrace. * * Semantic: just dispatch from here and leave whatever stacktrace is * in the exception object. */voidthrowExternalException(Hjava_lang_Throwable* eobj){	if (eobj == 0) {		dprintf("Exception thrown on null object ... aborting\n");		ABORT();		EXIT(1);	}	dispatchException(eobj, (stackTraceInfo*)buildStackTrace(0));}#if 0voidthrowOutOfMemory(void){	Hjava_lang_Throwable* err;	err = OutOfMemoryError;	if (err != NULL) {		throwException(err);	}	dprintf("(Insufficient memory)\n");	EXIT(-1);}#endifstatic voiddispatchException(Hjava_lang_Throwable* eobj, stackTraceInfo* baseFrame){	threadData*		thread_data;	VmExceptHandler*	lastJniFrame;	stackTraceInfo*		frame;#if defined(INTS_DISABLED)	/*	 * We should never try to dispatch an exception while interrupts are	 * disabled.  If the threading system provides a means to do so,	 * check that we don't attempt to do it anyway.	 */	assert(!INTS_DISABLED());#endif	thread_data = THREAD_DATA(); 	/* Save exception object */	thread_data->exceptObj = eobj;#if defined (HAVE_GCJ_SUPPORT)	/* XXX */	_Jv_Throw(eobj); /* no return */#endif	/* Search down exception stack for a match */	DBG(ELOOKUP,	    dprintf ("dispatchException(): %s\n", ((Hjava_lang_Object*)eobj)->dtable->class->name->data);)	/*	 * find the last jni frame	 * (there is _always_ a jni frame somewhere on the stack,	 *  except during initialiseKaffe() )	 */	for (lastJniFrame = thread_data->exceptPtr;	     lastJniFrame && !vmExcept_isJNIFrame(lastJniFrame);	     lastJniFrame = lastJniFrame->prev);	/*	 * now walk up the stack 	 */	for (frame = baseFrame; frame->meth != ENDOFSTACK; frame++) {		bool 			foundHandler;		uintp 			handler;		Hjava_lang_Object*	obj;		/*		 * if we reach the last jni frame, we're done		 */		if (lastJniFrame && vmExcept_JNIContains(lastJniFrame, frame->fp)) {			thread_data->exceptPtr = lastJniFrame;			vmExcept_jumpToHandler(lastJniFrame); /* doesn't return */		}		/*		 * if we could not determine the java method of this stack frame,		 * simply ignore that frame		 */		if (frame->meth == 0) {			continue;		}		/*		 * check whether that method contains a suitable handler		 */		foundHandler = findExceptionBlockInMethod(frame->pc,							  eobj->base.dtable->class,							  frame->meth,							  &handler);		/* Find the sync. object */		if ((frame->meth->accflags & ACC_SYNCHRONISED)==0) {			obj = 0;		} else if (frame->meth->accflags & ACC_STATIC) {			obj = &frame->meth->class->head;		} else {			FRAMEOBJECT(obj, frame->fp, frame->meth);		}		/* If handler found, call it */		if (foundHandler) {			thread_data->needOnStack = STACK_HIGH;			DISPATCH_EXCEPTION(frame->fp, handler, eobj); /* doesn't return */		}#if defined(ENABLE_JVMPI)		soft_exit_method(frame->meth);#endif		/* If not here, exit monitor if synchronised. */		if (frame->meth->accflags & ACC_SYNCHRONISED) {			locks_internal_slowUnlockMutexIfHeld(&obj->lock, (void *)frame->fp, 0);		}	    		/* If method found and profiler enable, fix self+children time */#if defined(TRANSLATOR) && defined(KAFFE_PROFILER)		if (profFlag) {			profiler_click_t end;			profiler_get_clicks(end);			frame->meth->totalClicks += end;		}#endif    	}	/*	 * we did not find a handler...	 */	unhandledException (eobj);}voidunhandledException(Hjava_lang_Throwable *eobj){	const char* cname;	Hjava_lang_Class* class;	/* Clear held exception object */	THREAD_DATA()->exceptObj = 0;	class = OBJECT_CLASS(&eobj->base);	cname = CLASS_CNAME(class);	/* We must catch 'java.lang.ThreadDeath' exceptions now and	 * kill the thread rather than the machine.	 */	if (strcmp(cname, THREADDEATHCLASS) == 0) {		exitThread();	}	/* We don't know what to do here. */	dprintf("Internal error: caught an unexpected exception.\n"		"Please check your CLASSPATH and your installation.\n");	/*	 * Display the exception and stack trace to help in debugging.	 */	{		Hjava_lang_String *msg;		msg = unhand((Hjava_lang_Throwable*)eobj)->detailMessage;		if (msg) {			dprintf("%s: %s\n", cname, stringJava2C(msg));		} else {			dprintf("%s\n", cname);		}	}	printStackTrace((Hjava_lang_Throwable*)eobj, 0, 1);	ABORT();}/* * Setup the internal exceptions. */voidinitExceptions(void){DBG(INIT,	dprintf("initExceptions()\n");    )	/* Catch signals we need to convert to exceptions */	jthread_initexceptions(nullException, floatingException);}/* * Null exception - catches bad memory accesses. */static voidnullException(struct _exceptionFrame *frame){	Hjava_lang_Throwable* npe;	Hjava_lang_VMThrowable* vmstate;	Hjava_lang_Object* backtrace;	npe = (Hjava_lang_Throwable*)newObject(javaLangNullPointerException);	vmstate = (Hjava_lang_VMThrowable*)newObject(javaLangVMThrowable);	backtrace = buildStackTrace(frame);	unhand(vmstate)->backtrace = backtrace;	unhand(npe)->vmState = vmstate;#if defined(HAVE_GCJ_SUPPORT)	FAKE_THROW_FRAME();#endif /* defined(HAVE_GCJ_SUPPORT) */	dispatchException(npe, (stackTraceInfo*)backtrace);}/* * Division by zero. */static voidfloatingException(struct _exceptionFrame *frame){	Hjava_lang_Throwable* ae;	Hjava_lang_VMThrowable* vmstate;	Hjava_lang_Object* backtrace;	ae = (Hjava_lang_Throwable*)newObject(javaLangArithmeticException);	vmstate = (Hjava_lang_VMThrowable*)newObject(javaLangVMThrowable);	backtrace = buildStackTrace(frame);	unhand(vmstate)->backtrace = backtrace;	unhand(ae)->vmState = vmstate;#if defined(HAVE_GCJ_SUPPORT)	FAKE_THROW_FRAME();#endif /* defined(HAVE_GCJ_SUPPORT) */	dispatchException(ae, (stackTraceInfo*)backtrace);}/* * 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 boolfindExceptionBlockInMethod(uintp pc, Hjava_lang_Class* class, Method* ptr, uintp* handler){	jexceptionEntry* eptr;	Hjava_lang_Class* cptr;	int i;	assert(handler);	eptr = &ptr->exception_table->entry[0];	/* Right method - look for exception */	if (ptr->exception_table == 0) {DBG(ELOOKUP,		dprintf("%s.%s has no handlers.\n", ptr->class->name->data, ptr->name->data); )		return (false);	}DBG(ELOOKUP,	dprintf("%s.%s has %d handlers (throw was pc=%#lx):\n",		ptr->class->name->data, ptr->name->data,		ptr->exception_table->length, (long) pc); )	for (i = 0; i < ptr->exception_table->length; i++) {		uintp start_pc = eptr[i].start_pc;		uintp end_pc = eptr[i].end_pc;		uintp handler_pc = eptr[i].handler_pc;DBG(ELOOKUP,	dprintf("  Handler %d covers %#lx-%#lx\n", i, 			(long) start_pc, (long) end_pc); )		if (pc < start_pc || pc >= end_pc) {			continue;		}		/* Found exception - is it right type */		if (eptr[i].catch_idx == 0) {			*handler = handler_pc;DBG(ELOOKUP,		dprintf("  Found handler @ %#lx: catches all exceptions.\n", 				(long) handler_pc); )			return (true);		}		/* Did I try to resolve that catch type before */		if (eptr[i].catch_type == UNRESOLVABLE_CATCHTYPE) {DBG(ELOOKUP,		dprintf("  Found handler @ %#lx: Unresolvable catch type.\n", 				(long) handler_pc); )			return (false);		}		/* Resolve catch class if necessary */		if (eptr[i].catch_type == NULL) {			/*			 * XXX Since we pre-load all catch clause exceptions			 * in code-analyse.c now, this code should never			 * be called.  Right?			 */			errorInfo info;			eptr[i].catch_type = getClass(eptr[i].catch_idx, ptr->class, &info);			/*			 * If we could not resolve the catch class, then we			 * must a) record that fact to guard against possible			 * recursive attempts to load it and b) throw the error			 * resulting from that failure and forget about the			 * current exception.			 */			if (eptr[i].catch_type == NULL) {DBG(ELOOKUP|DBG_RESERROR,				dprintf("Couldn't resolve catch class @ cp idx=%d\n",					eptr[i].catch_idx); )				eptr[i].catch_type = UNRESOLVABLE_CATCHTYPE;				throwError(&info);				return (false);			}		}                for (cptr = class; cptr != 0; cptr = cptr->superclass) {                        if (cptr == eptr[i].catch_type) {DBG(ELOOKUP,	dprintf("  Found matching handler at %#lx: Handles %s.\n",			(long) handler_pc, CLASS_CNAME(eptr[i].catch_type)); )                                *handler = handler_pc;                                return (true);                        }                }DBG(ELOOKUP,	dprintf("  Handler at %#lx (handles %s), does not match.\n",			(long) handler_pc, CLASS_CNAME(eptr[i].catch_type)); )	}	return (false);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -