[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