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 + -
显示快捷键?