classmethod.c

来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· C语言 代码 · 共 2,775 行 · 第 1/5 页

C
2,775
字号
/* * classMethod.c * Dictionary of classes, methods and fields. * * Copyright (c) 1996, 1997 *	Transvirtual Technologies, Inc.  All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. */#include "config.h"#include "debug.h"#include "config-std.h"#include "config-mem.h"#include "config-hacks.h"#include "gtypes.h"#include "slots.h"#include "access.h"#include "object.h"#include "errors.h"#include "code.h"#include "file.h"#include "readClass.h"#include "baseClasses.h"#include "stringSupport.h"#include "stackTrace.h"#include "thread.h"#include "jthread.h"#include "itypes.h"#include "bytecode.h"#include "exception.h"#include "classMethod.h"#include "md.h"#include "external.h"#include "lookup.h"#include "support.h"#include "stats.h"#include "gc.h"#include "locks.h"#include "md.h"#include "jni.h"#include "soft.h"#include "methodCache.h"#include "gcj/gcj.h"#include "xprofiler.h"#include "jvmpi_kaffe.h"#if 0#define	METHOD_TRUE_NCODE(METH)			(METH)->c.ncode.ncode_start#define	METHOD_PRE_COMPILED(METH)		((int16)(METH)->localsz < 0)#define	SET_METHOD_PRE_COMPILED(METH, VAL)	((METH)->localsz = -(VAL))#endif/* interfaces supported by arrays */static Hjava_lang_Class* arr_interfaces[2];extern bool verify2(Hjava_lang_Class*, errorInfo*);extern bool verify3(Hjava_lang_Class*, errorInfo*);static int internalSetupClass(Hjava_lang_Class*, Utf8Const*, int, int, int, Hjava_lang_ClassLoader*, errorInfo *einfo);static bool buildDispatchTable(Hjava_lang_Class*, errorInfo *info);static bool buildInterfaceDispatchTable(Hjava_lang_Class*, errorInfo *);static bool checkForAbstractMethods(Hjava_lang_Class* class, errorInfo *einfo);static bool prepareInterface(Hjava_lang_Class*, errorInfo*);static bool computeInterfaceImplementationIndex(Hjava_lang_Class*, errorInfo*);static bool allocStaticFields(Hjava_lang_Class*, errorInfo *einfo);static bool resolveObjectFields(Hjava_lang_Class*, errorInfo *einfo);static bool resolveStaticFields(Hjava_lang_Class*, errorInfo *einfo);static bool resolveConstants(Hjava_lang_Class*, errorInfo *einfo);static bool resolveInterfaces(Hjava_lang_Class *class, errorInfo *einfo);#if !defined(ALIGNMENT_OF_SIZE)#define	ALIGNMENT_OF_SIZE(S)	(S)#endif/* set a class's alloc_type field */voiddetermineAllocType(Hjava_lang_Class *class){        if (StringClass != 0 && instanceof(StringClass, class)) {                class->alloc_type = GC_ALLOC_JAVASTRING;        } else        if (ClassLoaderClass != 0 && instanceof(ClassLoaderClass, class)) {                class->alloc_type = GC_ALLOC_JAVALOADER;        } else        if (class->finalizer != 0) {                class->alloc_type = GC_ALLOC_FINALIZEOBJECT;        } else {                class->alloc_type = GC_ALLOC_NORMALOBJECT;        }}/* * Process all the stage of a classes initialisation.  We can provide * a state to aim for (so we don't have to do this all at once).  This * is called by various parts of the machine in order to load, link * and initialise the class.  Putting it all together here makes it a damn * sight easier to understand what's happening. * * Returns true if processing was successful, false otherwise. */boolprocessClass(Hjava_lang_Class* class, int tostate, errorInfo *einfo){	Method* meth;	classEntry *ce;	Hjava_lang_Class* nclass;	bool success = true;	/* optimistic */#if !(defined(NDEBUG) || !defined(KAFFE_VMDEBUG))	int i;	static int depth;#endif /* !(defined(NDEBUG) || !defined(KAFFE_VMDEBUG)) */	static Method *object_fin;	int iLockRoot;	/* If this class is initialised to the required point, quit now */	if (class->state >= tostate) {		return (true);	}#define	SET_CLASS_STATE(S)	class->state = (S)#define	DO_CLASS_STATE(S)	if ((S) > class->state && (S) <= tostate)	/* For the moment we only allow one thread to initialise any classes	 * at once.  This is because we've got circular class dependencies	 * we've got to work out.	 */	/*	 * Get the entry for this class, we'll need to update its state along	 * the way.	 */	ce = lookupClassEntryInternal(class->name, class->loader);	lockClass(class);DBG(RESERROR,	/* show calls to processClass when debugging resolution errors */	depth++;	for (i = 0; i < depth; dprintf("  "), i++);	dprintf("%p entering process class %s %d->%d\n",		jthread_current(), class->name->data,		class->state, tostate);    )retry:	/* If the initialization of that class failed once before, don't	 * bother and report that no definition for this class exists.	 * We must do that after the retry label so that threads waiting	 * on other threads performing a particular initialization step	 * can learn that things went wrong.	 */	if (class->state == CSTATE_FAILED) {		postExceptionMessage(einfo,				     JAVA_LANG(NoClassDefFoundError),				     "%s",				     class->name->data);		einfo->type |= KERR_NO_CLASS_FOUND; /* for the verifier */		success = false;		goto done;	}	DO_CLASS_STATE(CSTATE_LOADED_SUPER) {		setClassMappingState(ce, NMS_LOADING);				class->processingThread = THREAD_NATIVE();				/* Load and link the super class */		if( class->superclass )		{			/*			 * propagate failures in super class loading and			 * processing.  Since getClass might involve an			 * upcall to a classloader, we must release the			 * classLock here.			 */			unlockClass(class);			#if defined(HAVE_GCJ_SUPPORT)			if( CLASS_GCJ(class) )			{				class->superclass					= gcjGetClass((void*)class->superclass,						      einfo);			}			else#endif			{				class->superclass =					getClass((uintp)class->superclass,						 class,						 einfo);			}						lockClass(class);			if( class->superclass == 0 )			{				success = false;				goto done;			}			if( !(class->accflags & ACC_INTERFACE) &&			    (class->superclass->accflags & ACC_INTERFACE)) {				postExceptionMessage(					einfo,					JAVA_LANG(						IncompatibleClassChangeError),					"Super class, %s, is an interface.",					class->superclass->name->data);				success = false;				goto done;			}			/* that's pretty much obsolete. */			assert(class->superclass->state >= CSTATE_DOING_LINK);			classMappingLoaded(ce, class);			/* Copy initial field size and gc layout.			 * Later, as this class's fields are resolved, they			 * are added to the superclass's layout.			 */			CLASS_FSIZE(class) = CLASS_FSIZE(class->superclass);			class->gc_layout = class->superclass->gc_layout;		}		if( class->superclass )		{			assert(class->superclass->state >= CSTATE_DOING_LINK);		}			}		DO_CLASS_STATE(CSTATE_VERIFIED) {		/*		 * Second stage verification - check the class format is okay		 */		success =  verify2(class, einfo);		if (success == false) {			goto done;		}		SET_CLASS_STATE(CSTATE_VERIFIED);	}		DO_CLASS_STATE(CSTATE_PREPARED) {		if( (class->loader == 0) && !gc_add_ref(class) )		{			postOutOfMemory(einfo);			success = false;			goto done;		}		/* Allocate any static space required by class and initialise		 * the space with any constant values.  This isn't necessary		 * for pre-loaded classes.		 */		if (class->state != CSTATE_PRELOADED		    && !allocStaticFields(class, einfo)) {			success = false;			goto done;		}		SET_CLASS_STATE(CSTATE_DOING_PREPARE);		class->processingThread = THREAD_NATIVE();#if defined(HAVE_GCJ_SUPPORT)		if (CLASS_GCJ(class)) {			success = gcjProcessClass(class, class->gcjPeer, einfo);			if (success == false) {				goto done;			}		}#else/* #warning No GCJ Support */#endif		success = resolveObjectFields(class, einfo);		if (success == false) {			goto done;		}		success = resolveStaticFields(class, einfo);		if (success == false) {			goto done;		}		success = resolveInterfaces(class, einfo);		if (success == false) {			goto done;		}		/* Build dispatch table.  We must handle interfaces a little		 * differently since they only have a <clinit> method.		 */		if (!CLASS_IS_INTERFACE(class)) {			success = buildDispatchTable(class, einfo);			if (success == false) {				goto done;			}			success = buildInterfaceDispatchTable(class, einfo);			if (success == false) {				goto done;			}			success = checkForAbstractMethods(class, einfo);			if (success == false) {				goto done;			}			success = computeInterfaceImplementationIndex(class,								      einfo);		} else {			success = prepareInterface(class, einfo);		}		if (success == false) {			goto done;		}		SET_CLASS_STATE(CSTATE_PREPARED);				setClassMappingState(ce, NMS_DONE);		#if defined(ENABLE_JVMPI)		if( JVMPI_EVENT_ISENABLED(JVMPI_EVENT_CLASS_LOAD) )		{			JVMPI_Method *jvmpi_methods;			JVMPI_Field *jvmpi_fields;			JVMPI_Event ev;						jvmpi_methods = alloca(sizeof(JVMPI_Method) *					       class->nmethods);			jvmpi_fields = alloca(sizeof(JVMPI_Field) *					      (class->nsfields +					       class->nfields));			ev.u.class_load.methods = jvmpi_methods;			ev.u.class_load.statics = &jvmpi_fields[0];			ev.u.class_load.instances =				&jvmpi_fields[class->nsfields];			jvmpiFillClassLoad(&ev, class);			jvmpiPostEvent(&ev);		}#endif	}	assert((class == ObjectClass) || (class->superclass != NULL));	DO_CLASS_STATE(CSTATE_LINKED) {				if (class->state == CSTATE_DOING_LINK) {			if (THREAD_NATIVE() == class->processingThread) {				goto done;			} else {				while (class->state == CSTATE_DOING_LINK) {					waitOnClass(class);					goto retry;				}			}		}				SET_CLASS_STATE(CSTATE_DOING_LINK);				/* Third stage verification - check the bytecode is okay */		success = verify3(class, einfo);		if (success == false) {			goto done;		}		SET_CLASS_STATE(CSTATE_LINKED);	}	/* NB: the reason that CONSTINIT is a separate state is that	 * CONSTINIT depends on StringClass, which isn't available during	 * initialization when we bring the base classes to the LINKED state.	 */	DO_CLASS_STATE(CSTATE_CONSTINIT) {#if defined(HAVE_GCJ_SUPPORT)		int i;                Field *fld;		if (CLASS_GCJ(class)) {			success = gcjProcessClassConstants(class,							   class->gcjPeer,							   einfo);			if (success == false) {				goto done;			}		}		/* We must resolve field types eagerly so that class gc		 * will mark static fields of gcj classes.  That walking		 * depends on whether the UNRESOLVED_FLAG is clear.		 */		fld = CLASS_FIELDS(class);		for (i = 0; i < CLASS_NFIELDS(class); fld++, i++) {			if (resolveFieldType(fld, class, einfo) == 0) {				success = false;				goto done;			}		}#endif /* defined(HAVE_GCJ_SUPPORT) */		/* Initialise the constants */		success = resolveConstants(class, einfo);		if (success == false) {			goto done;		}		/* And note that it's done */		SET_CLASS_STATE(CSTATE_CONSTINIT);	}	DO_CLASS_STATE(CSTATE_USABLE) {		/* If somebody's already processing the super class,		 * check whether it's us.  If so, return.		 * Else, wait for the other thread to complete and		 * start over to reevaluate the situation.		 */		if (class->state == CSTATE_DOING_SUPER) {			if (THREAD_NATIVE() == class->processingThread) {				goto done;			} else {				while (class->state == CSTATE_DOING_SUPER) {					waitOnClass(class);					goto retry;				}			}		}		SET_CLASS_STATE(CSTATE_DOING_SUPER);		/* Now determine the method used to finalize this object.		 * If the finalizer is empty, we set class->finalizer to null.		 * Find finalizer first without calling findMethod.		 */		meth = 0;		for (nclass = class; nclass != 0; nclass = nclass->superclass) {			meth = findMethodLocal(nclass, final_name, void_signature);			if (meth != NULL) {				break;			}		}		/* every class must have one since java.lang.Object has one */		if (meth == NULL) {			postException(einfo, JAVA_LANG(InternalError));			success = false;			goto done;		}		/* is it empty?  This test should work even if an		 * object has been finalized before this class is		 * loaded. If Object.finalize() is empty, save a pointer		 * to the method itself, and check meth against it in		 * the future.		 */		if ((meth->c.bcode.codelen == 1		     && meth->c.bcode.code[0] == RETURN)) {			if (!object_fin && meth->class == ObjectClass) {				object_fin = meth;			}			class->finalizer = 0;		} else if (meth == object_fin) {			class->finalizer = 0;		} else {			class->finalizer = meth;		}		determineAllocType(class);		if (class->superclass != NULL) {			class->processingThread = THREAD_NATIVE();			/* We must not hold the class lock here because we			 * might call out into the superclass's initializer			 * here!			 */			unlockClass(class);			success = processClass(class->superclass,					       CSTATE_COMPLETE,					       einfo);			lockClass(class);			if (success == false) {				if (class->superclass->state == CSTATE_FAILED)					SET_CLASS_STATE(CSTATE_FAILED);				goto done;			}		}		SET_CLASS_STATE(CSTATE_USABLE);	}	DO_CLASS_STATE(CSTATE_COMPLETE) {		JNIEnv *env = THREAD_JNIENV();		jthrowable exc = 0;		JavaVM *vms[1];		jsize jniworking;		/* If we need a successfully initialized class here, but its		 * initializer failed, return false as well		 */		if (class->state == CSTATE_FAILED) {			postExceptionMessage(einfo,				JAVA_LANG(NoClassDefFoundError),				"%s", class->name->data);			success = false;			goto done;		}DBG(STATICINIT, dprintf("Initialising %s static %d\n", class->name->data,			CLASS_FSIZE(class)); 	)		meth = findMethodLocal(class, init_name, void_signature);		if (meth == NULL) {			SET_CLASS_STATE(CSTATE_COMPLETE);			goto done;		}		if (class->state == CSTATE_DOING_INIT) {			if (THREAD_NATIVE() == class->processingThread) {				goto done;			} else {				while (class->state == CSTATE_DOING_INIT) {					waitOnClass(class);					goto retry;				}			}		}		SET_CLASS_STATE(CSTATE_DOING_INIT);		class->processingThread = THREAD_NATIVE();		/* give classLock up for the duration of this call */		unlockClass(class);		/* we use JNI to catch possible exceptions, except		 * during initialization, when JNI doesn't work yet.		 * Should an exception occur at that time, we're		 * lost anyway.		 */		JNI_GetCreatedJavaVMs(vms, 1, &jniworking);		if (jniworking) {DBG(STATICINIT,			dprintf("using JNI\n");)			(*env)->ExceptionClear(env);			(*env)->CallStaticVoidMethodA(env, class, meth, 0);			exc = (*env)->ExceptionOccurred(env);			(*env)->ExceptionClear(env);		} else {

⌨️ 快捷键说明

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