classmethod.c

来自「基于LWVCL开发的库」· C语言 代码 · 共 2,711 行 · 第 1/5 页

C
2,711
字号
/* * classMethod.c * Dictionary of classes, methods and fields. * * Copyright (c) 1996, 1997, 2004 *	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 "defs.h"#include "gtypes.h"#include "machine.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 "gcj/gcj.h"#include "xprofiler.h"#include "debugFile.h"#include "jvmpi_kaffe.h"#include "kaffe/jmalloc.h"#include "methodcalls.h"/* 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);static parsed_signature_t *duplicateParsedSignature (parsed_signature_t *, errorInfo *);static struct Hjava_security_ProtectionDomain  *defaultProtectionDomain;voidinitialiseSecurity (void){	struct Hjava_lang_Object *codeSource;	struct Hjava_lang_Object *permissions;	struct Hjava_lang_Object *allPermission;        DBG(INIT, dprintf("initialiseSecurity()\n"); );	codeSource = execute_java_constructor ("java/security/CodeSource",					       NULL,					       NULL,					       "(Ljava/net/URL;[Ljava/security/cert/Certificate;)V",					       NULL,					       NULL);	permissions = execute_java_constructor ("java/security/Permissions",						NULL,						NULL,						"()V");	allPermission = execute_java_constructor ("java/security/AllPermission",						  NULL,						  NULL,						  "()V");		do_execute_java_method(NULL, permissions, "add", "(Ljava/security/Permission;)V",			       NULL, 0, allPermission);	do_execute_java_method(NULL, permissions, "setReadOnly", "()V", NULL, 0);	defaultProtectionDomain = (struct Hjava_security_ProtectionDomain *)execute_java_constructor ("java/security/ProtectionDomain",							    NULL,							    NULL,							    "(Ljava/security/CodeSource;Ljava/security/PermissionCollection;)V",							    codeSource,							    permissions);        DBG(INIT, dprintf("initialiseSecurity() done\n"); );}#if !defined(ALIGNMENT_OF_SIZE)#define	ALIGNMENT_OF_SIZE(S)	(S)#endif/* set a class's alloc_type field */static voiddetermineAllocType(Hjava_lang_Class *class){  if (StringClass != 0 && StringClass == class)    class->alloc_type = KGC_ALLOC_JAVASTRING;  else    if (ClassLoaderClass != 0 && instanceof(ClassLoaderClass, class))      class->alloc_type = KGC_ALLOC_JAVALOADER;    else      class->alloc_type = KGC_ALLOC_FINALIZEOBJECT;}/* * 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;	/* 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",		KTHREAD(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((constIndex)(uintp)class->superclass,						 class,						 einfo);			}						lockClass(class);			if( class->superclass == 0 )			{				success = false;				goto done;			}			KGC_addWeakRef(main_collector, 				       class->superclass, 				       (void **)&(class->superclass));			if( !(class->accflags & ACC_INTERFACE) &&			    (getSuperclass(class)->accflags & ACC_INTERFACE)) {				postExceptionMessage(					einfo,					JAVA_LANG(						IncompatibleClassChangeError),					"Super class, %s, is an interface.",					getSuperclass(class)->name->data);				success = false;				goto done;			}			/* that's pretty much obsolete. */			assert(getSuperclass(class)->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(getSuperclass(class));			class->gc_layout = getSuperclass(class)->gc_layout;		}		if( class->superclass )		{			assert(getSuperclass(class)->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(class));			jvmpi_fields = alloca(sizeof(JVMPI_Field) *					      (class->nsfields +					       CLASS_NFIELDS(class)));			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 = NULL;		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 = NULL;		} else if (meth == object_fin) {			class->finalizer = NULL;		} 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 (getSuperclass(class)->state == CSTATE_FAILED)					SET_CLASS_STATE(CSTATE_FAILED);				goto done;			}		}#if defined(KAFFE_XDEBUGGING)		if( machine_debug_file )		{			addDebugInfo(machine_debug_file,				     DIA_Class, class,				     DIA_DONE);		}#endif				SET_CLASS_STATE(CSTATE_USABLE);	}

⌨️ 快捷键说明

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