[kaffe] CVS kaffe (guilhem): itable2dtable fix.

Kaffe CVS cvs-commits at kaffe.org
Mon Apr 25 09:05:52 PDT 2005


PatchSet 6421 
Date: 2005/04/25 16:01:42
Author: guilhem
Branch: HEAD
Tag: (none) 
Log:
itable2dtable fix.

        * kaffe/kaffevm/classMethod.c
        (buildInterfaceDispatchTable): Put a strong reference on itable2dtable
        to prevent it being freed before the class is actually destroyed.

        * kaffe/kaffevm/gcFuncs.c
        (destroyClass): Remove strong reference on itable2dtable.

Members: 
	ChangeLog:1.3949->1.3950 
	kaffe/kaffevm/classMethod.c:INITIAL->1.140 
	kaffe/kaffevm/gcFuncs.c:1.70->1.71 

Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.3949 kaffe/ChangeLog:1.3950
--- kaffe/ChangeLog:1.3949	Sun Apr 24 15:10:43 2005
+++ kaffe/ChangeLog	Mon Apr 25 16:01:42 2005
@@ -1,3 +1,12 @@
+2005-04-25  Guilhem Lavaux  <guilhem at kaffe.org>
+
+	* kaffe/kaffevm/classMethod.c
+	(buildInterfaceDispatchTable): Put a strong reference on itable2dtable
+	to prevent it being freed before the class is actually destroyed.
+
+	* kaffe/kaffevm/gcFuncs.c
+	(destroyClass): Remove strong reference on itable2dtable.
+
 2005-04-24  Eric Anholt <eta at lclark.edu>
 
 	* kaffe/kaffevm/exception.c,
===================================================================
Checking out kaffe/kaffe/kaffevm/classMethod.c
RCS:  /home/cvs/kaffe/kaffe/kaffe/kaffevm/classMethod.c,v
VERS: 1.140
***************
--- /dev/null	Sun Aug  4 19:57:58 2002
+++ kaffe/kaffe/kaffevm/classMethod.c	Mon Apr 25 16:05:52 2005
@@ -0,0 +1,2907 @@
+/*
+ * 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 "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 "debugFile.h"
+#include "jvmpi_kaffe.h"
+#include "kaffe/jmalloc.h"
+#include "methodcalls.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 */
+static void
+determineAllocType(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.
+ */
+bool
+processClass(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, &(class->superclass));
+			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(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 (class->superclass->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);
+	}
+
+	DO_CLASS_STATE(CSTATE_COMPLETE) {
+		jthrowable exc = NULL;
+		jthrowable excpending;
+
+		/* 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 here an exception safe call method to be able
+		 * to catch possible exceptions which may occur.
+		 */
+		excpending = THREAD_DATA()->exceptObj;
+		THREAD_DATA()->exceptObj = NULL;
+
+		KaffeVM_safeCallMethodA(meth, METHOD_NATIVECODE(meth), NULL, NULL, NULL, 0);
+		exc = THREAD_DATA()->exceptObj;
+		THREAD_DATA()->exceptObj = excpending;
+
+		lockClass(class);
+
+		class->processingThread = NULL;
+		
+		if (exc != 0) {
+			if( soft_instanceof(javaLangException, exc) )
+			{
+				/* this is special-cased in throwError */
+				einfo->type = (KERR_INITIALIZER_ERROR |
+					       KERR_NO_CLASS_FOUND);
+				einfo->throwable = exc;
+			}
+			else
+			{
+				/* Should be an error... */
+				einfo->type = (KERR_RETHROW |
+					       KERR_NO_CLASS_FOUND);
+				einfo->throwable = exc;
+			}
+			
+			/*
+			 * we return false here because COMPLETE fails
+			 */
+			success = false;
+			SET_CLASS_STATE(CSTATE_FAILED);
+		} else {
+			SET_CLASS_STATE(CSTATE_COMPLETE);
+		}
+
+		/* Since we'll never run this again we might as well
+		 * lose it now. However, if there was an exception, keep
+		 * it so the stack trace doesn't lose the <clinit> frame.
+		 */
+#if defined(TRANSLATOR) && (defined (MD_UNREGISTER_JIT_EXCEPTION_INFO) || defined (JIT3))
+#if defined(MD_UNREGISTER_JIT_EXCEPTION_INFO)
+		if (exc == 0) {
+			MD_UNREGISTER_JIT_EXCEPTION_INFO (meth->c.ncode.ncode_start,
+							  METHOD_NATIVECODE(meth),
+							  meth->c.ncode.ncode_end);
+		}
+#endif
+#endif
+		if (
+#if defined(JIT3)
+		    (exc == 0) &&
+#endif
+#if defined(KAFFE_XPROFILER)
+		    !xProfFlag &&
+#endif
+		    1) {
+			_SET_METHOD_NATIVECODE(meth, NULL);
+			meth->c.ncode.ncode_start = NULL;
+			meth->c.ncode.ncode_end = NULL;
+		}
+	}
+
+done:
+	/* If anything ever goes wrong with this class, we declare it dead
+	 * and will respond with NoClassDefFoundErrors to any future attempts
+	 * to access that class.
+	 * NB: this does not include when a static initializer failed.
+	 */
+	if (success == false && class->state != CSTATE_FAILED) {
+		SET_CLASS_STATE(CSTATE_FAILED);
+
+		if( ce->state != NMS_DONE )
+		{
+			setClassMappingState(ce, NMS_EMPTY);
+		}
+	}
+
+	/* wake up any waiting threads */
+	broadcastOnClass(class);
+	unlockClass(class);
+
+DBG(RESERROR,
+	for (i = 0; i < depth; dprintf("  "), i++);
+	depth--;
+	dprintf("%p leaving process class %s -> %s\n",
+		KTHREAD(current)(), class->name->data,
+		success ? "success" : "failure");
+    );
+	return (success);
+}
+
+static int
+expandMethods(Hjava_lang_Class *cl, Method *imeth, errorInfo *einfo)
+{
+	Method *new_methods = NULL;
+	int retval = 0;
+	
+	/*
+	if( !CLASS_IS_ABSTRACT(cl) )
+	{
+		postExceptionMessage(einfo,
+				     JAVA_LANG(ClassFormatError),
+				     "(class: %s, method: %s signature: %s) "
+				     "Abstract method in non-abstract class",
+				     cl->name->data,
+				     imeth->name->data,
+				     imeth->parsed_sig->signature->data);
+	}
+	else
+	*/
+	if( (new_methods = gc_realloc(CLASS_METHODS(cl),
+				      sizeof(Method) *
+				      (CLASS_NMETHODS(cl) + 1), KGC_ALLOC_METHOD)) )
+	{
+		int i;
+		
+		i = CLASS_NMETHODS(cl);
+		CLASS_NMETHODS(cl) = i + 1;
+		CLASS_METHODS(cl) = new_methods;
+		utf8ConstAddRef(imeth->name);
+		utf8ConstAddRef(imeth->parsed_sig->signature);
+		new_methods[i] = *imeth;
+		new_methods[i].ndeclared_exceptions = -1;
+		new_methods[i].declared_exceptions_u.remote_exceptions =
+			imeth;
+		new_methods[i].class = cl;
+		retval = 1;
+	}
+	else
+	{
+		gc_free(new_methods);
+		postOutOfMemory(einfo);
+	}
+	return( retval );
+}
+
+static int
+expandInterfaces(Hjava_lang_Class *root_class,
+		 Hjava_lang_Class *class,
+		 errorInfo *einfo)
+{
+	int i, j, k, success = 1;
+	
+	/*
+	 * Check to make sure all the interface methods are implemented,
+	 * otherwise, we'll need to add a slot.
+	 */
+	for( i = 0; (i < class->interface_len) && success; i++ )
+	{
+		Hjava_lang_Class *iface;
+		
+		iface = class->interfaces[i];
+		if( !expandInterfaces(root_class, iface, einfo) )
+		{
+			success = 0;
+			break;
+		}
+		for( j = 0; (j < CLASS_NMETHODS(iface)) && success; j++ )
+		{
+			Hjava_lang_Class *cl;
+			int foundit = 0;
+			Method *imeth;
+			
+			imeth = &CLASS_METHODS(iface)[j];
+			/* Igore statics */
+			if( imeth->accflags & ACC_STATIC )
+				continue;
+			/* Search for the corresponding slot. */
+			for( cl = root_class;
+			     cl && !foundit;
+			     cl = cl->superclass )
+			{
+				for( k = 0; k < CLASS_NMETHODS(cl); k++ )
+				{
+					Method *cmeth;
+					
+					cmeth = &CLASS_METHODS(cl)[k];
+					if( (cmeth->name == imeth->name) &&
+					    (cmeth->parsed_sig->signature ==
+					     imeth->parsed_sig->signature) )
+					{
+						foundit = 1;
+						break;
+					}
+				}
+			}
+			if( !foundit )
+			{
+				/* No impl, add a slot */
+				success = expandMethods(root_class,
+							imeth,
+							einfo);
+			}
+		}
+	}
+	return( success );
+}
+
+static bool
+resolveInterfaces(Hjava_lang_Class *class, errorInfo *einfo)
+{
+	int i, j, k;
+	int totalilen;
+	Hjava_lang_Class** newifaces;
+	Hjava_lang_Class* nclass;
+	bool success = true;	/* optimistic */
+
+	/* Load all the implemented interfaces. */
+	j = class->interface_len;
+	nclass = class->superclass;
+	if (nclass != 0 && nclass != ObjectClass) {
+		/* If class is an interface, its superclass must
+		 * be java.lang.Object or the class file is broken.
+		 */
+		if (CLASS_IS_INTERFACE(class)) {
+			postException(einfo, JAVA_LANG(VerifyError));
+			success = false;
+			goto done;
+		}
+		j += class->superclass->total_interface_len;
+	}
+	for (i = 0; i < class->interface_len; i++) {
+		uintp iface = (uintp)class->interfaces[i];
+		unlockClass(class);
+
+#if defined(HAVE_GCJ_SUPPORT)
+		if (CLASS_GCJ(class)) {
+			nclass = gcjGetClass((void*)iface, einfo);
+		} else {
+			nclass = getClass(iface, class, einfo);
+		}
+#else
+		nclass = getClass(iface, class, einfo);
+#endif /* HAVE_GCJ_SUPPORT */
+
+		class->interfaces[i] = nclass;
+
+		lockClass(class);
+		if (class->interfaces[i] == 0) {
+			success = false;
+			goto done;
+		}
+		if (!(class->interfaces[i]->accflags & ACC_INTERFACE)) {
+			postExceptionMessage(
+				einfo,
+				JAVA_LANG(IncompatibleClassChangeError),
+				"Class, %s, used as interface by %s",
+				class->interfaces[i]->name->data,
+				class->name->data);
+			success = false;
+			goto done;
+		}
+		if (instanceof(class, class->interfaces[i])) {
+			postExceptionMessage(
+				einfo,
+				JAVA_LANG(ClassCircularityError),
+				"%s",
+				class->name->data);
+			success = false;
+			goto done;
+		}
+		j += class->interfaces[i]->total_interface_len;
+	}
+	totalilen = j;
+
+	/* We build a list of *all* interfaces this class can use */
+	if (class->interface_len != j) {
+		newifaces = (Hjava_lang_Class**)gc_malloc(sizeof(Hjava_lang_Class**) * j, KGC_ALLOC_INTERFACE);
+		if (newifaces == 0) {
+			postOutOfMemory(einfo);
+			success = false;
+			goto done;
+		}
+		for (i = 0; i < class->interface_len; i++) {
+			newifaces[i] = class->interfaces[i];
+		}
+		nclass = class->superclass;
+		if (nclass != 0 && nclass != ObjectClass) {
+			for (j = 0; j < nclass->total_interface_len; j++, i++) {
+				newifaces[i] = nclass->interfaces[j];
+			}
+		}
+		for (k = 0; k < class->interface_len; k++) {
+			nclass = class->interfaces[k];
+			for (j = 0; j < nclass->total_interface_len; j++, i++) {
+				newifaces[i] = nclass->interfaces[j];
+			}
+		}
+		class->interfaces = newifaces;
+	}
+
+	/* don't set total_interface_len before interfaces to avoid
+	 * having walkClass attempting to walk interfaces
+	 */
+	class->total_interface_len = totalilen;
+	
+	if( !CLASS_IS_INTERFACE(class) )
+	{
+		success = expandInterfaces(class, class, einfo);
+	}
+
+done:
+	return (success);
+}
+
+/**
+ * Check if a class name is in a set of packages.
+ *
+ * XXX Move somewhere else...
+ *
+ * @param plist The null terminated list of packages to check against.
+ * @param name The class name to check.
+ * @return True if the class name is in one of the packages, false otherwise.
+ */
+static int
+inPackageSet(const char **plist, Utf8Const *name)
+{
+	unsigned int name_len, lpc, retval = 0;
+	
+	name_len = strlen(name->data);
+	for( lpc = 0; plist[lpc] && !retval; lpc++ )
+	{
+		unsigned int len;
+
+		len = strlen(plist[lpc]);
+		if( (name_len > len) &&
+		    strncmp(name->data, plist[lpc], len) == 0 )
+		{
+			retval = 1;
+		}
+	}
+	return( retval );
+}
+
+/**
+ * The set of restricted packages that a user defined class loader can't add
+ * classes to.
+ */
+static const char *restrictedPackages[] = {
+	"java/",
+	"kaffe/",
+	NULL
+};
+
+static int
+internalSetupClass(Hjava_lang_Class* cl, Utf8Const* name, int flags,
+		   int this_index, int su, Hjava_lang_ClassLoader* loader,
+		   struct _errorInfo *einfo)
+{
+	if( (loader != NULL) &&
+	    inPackageSet(restrictedPackages, name) ) {
+		/*
+		 * Can't allow users to add classes to the bootstrap
+		 * packages.
+		 */
+		postExceptionMessage(einfo,
+				     JAVA_LANG(SecurityException),
+				     "Prohibited package: %s",
+				     name->data);
+		return 0;
+	}
+	if( cl->name == NULL ) {
+		utf8ConstAssign(cl->name, name);
+	}
+	else if( !utf8ConstEqual(cl->name, name) ) {
+		postExceptionMessage(einfo,
+				     JAVA_LANG(ClassFormatError),
+				     "%s (wrong name: %s)",
+				     name->data,
+				     cl->name->data);
+		return 0;
+	}
+	cl->packageLength = findPackageLength(name->data);
+	CLASS_METHODS(cl) = NULL;
+	CLASS_NMETHODS(cl) = 0;
+	assert(cl->superclass == 0);
+	cl->superclass = (Hjava_lang_Class*)(uintp)su;
+	cl->msize = 0;
+	CLASS_FIELDS(cl) = NULL;
+	CLASS_FSIZE(cl) = 0;
+	cl->accflags = flags;
+	cl->vtable = NULL;
+        cl->interfaces = NULL;
+	cl->interface_len = 0;
+	assert(cl->state < CSTATE_LOADED);
+	cl->state = CSTATE_LOADED;
+	cl->loader = loader;
+	cl->this_index = this_index;
+	cl->inner_classes = NULL;
+	cl->nr_inner_classes = 0;
+	cl->this_inner_index = -1;
+	return 1;
+}
+
+Hjava_lang_Class*
+setupClass(Hjava_lang_Class* cl, constIndex c, constIndex s,
+	   u2 flags, Hjava_lang_ClassLoader* loader,
+	   errorInfo* einfo)
+{
+	constants* pool;
+
+	pool = CLASS_CONSTANTS(cl);
+
+	/* Find the name of the class */

*** Patch too long, truncated ***




More information about the kaffe mailing list