classmethod.c
来自「基于LWVCL开发的库」· C语言 代码 · 共 2,711 行 · 第 1/5 页
C
2,711 行
* The itable maps the indices for each interface method to the * index in the dispatch table that corresponds to this interface * method. If a class does not implement an interface it declared, * or if it attempts to implement it with improper methods, the * dispatch table will have a 0xffffffff index. * (XXX is this 64bit safe?) * * This will cause a NoSuchMethodError * to be thrown later, in soft_lookupinterfacemethod. */ /* don't bother if we don't implement any interfaces */ if (class->total_interface_len == 0) { return (true); } class->if2itable = gc_malloc((class->total_interface_len + 1) * sizeof(short), KGC_ALLOC_CLASSMISC); if (class->if2itable == 0) { postOutOfMemory(einfo); return (false); } /* first count how many indices we need. We need at least one entry to put * the pointer to the class. */ j = 1; for (i = 0; i < class->total_interface_len; i++) { class->if2itable[i] = j; j += 1; /* add one word to store interface class */ j += class->interfaces[i]->msize; } /* This last entry is to specify the total length of the table. */ class->if2itable[class->total_interface_len] = j; class->itable2dtable = gc_malloc(j * sizeof(void *), KGC_ALLOC_INTERFACE_TABLE); if (class->itable2dtable == 0) { postOutOfMemory(einfo); return (false); } if (!gc_add_ref(class->itable2dtable)) { postOutOfMemory(einfo); return false; } class->itable2dtable[0] = class; j = 1; for (i = 0; i < class->total_interface_len; i++) { int inm = CLASS_NMETHODS(class->interfaces[i]); Method *imeth = Kaffe_get_class_methods(class->interfaces[i]); /* store interface as first word for type inclusion test */ class->itable2dtable[j++] = class->interfaces[i]; for (; inm--; imeth++) { Hjava_lang_Class* ncl; Method *cmeth = NULL; /* ignore static methods in interface --- can an * interface have any beside <clinit>? */ if (imeth->accflags & ACC_STATIC) { continue; } /* Search the actual method that implements this * interface method by name. */ for (ncl = class; ncl != NULL; ncl = ncl->superclass) { int k = CLASS_NMETHODS(ncl); cmeth = Kaffe_get_class_methods(ncl); for (; --k >= 0; ++cmeth) { if (utf8ConstEqual (cmeth->name, imeth->name) && utf8ConstEqual (METHOD_SIG(cmeth), METHOD_SIG(imeth))) { goto found; } } } /* not found */ cmeth = NULL; found:; /* constructors and static methods cannot implement * interface methods */ if (cmeth && (METHOD_IS_STATIC(cmeth) || METHOD_IS_CONSTRUCTOR(cmeth))) { cmeth = NULL; } /* cmeth == 0 if * This class does not implement the interface at all. * Or if the class attempts to implement an interface * method with a static method or constructor. */ if (cmeth == 0) { class->itable2dtable[j] = (void *)-1; } else { if (engine_buildTrampoline(cmeth, class->itable2dtable + j, einfo) == 0) { return (false); } } j++; } } return (true);}/* * Compute the interface implementation index for this class. * The impl_index is an index for each class that is used to index the * implementor table of the interface when dispatching an interface * method. See soft_lookupinterfacemethod in soft.c * It points directly at the first itable2dtable index for the section * that describes the interface (which is what's now redundantly stored * in if2itable[x].) * * This allows interface lookup in constant time. */static boolcomputeInterfaceImplementationIndex(Hjava_lang_Class* clazz, errorInfo* einfo){ int j, k; unsigned int i; int found_i; bool rc = false; Hjava_lang_Class** ifcs; /* find an impl_index for this class * Note that we only find a suitable impl_index with regard to the * interfaces this class implements, not a globally unique one. * * In other words, two classes implementing disjoint sets of * interfaces may end up with the same impl_index. For this reason, * the impl_index at this point cannot be used to implement the * equivalent of instanceof <interface> * * We assume that a verifier design is possible that will ensure * that a run-time object indeed implements an interface at the * time when soft_lookupinterfacemethod is invoked. We do not have * such a verifier at this point. */ if (clazz->total_interface_len == 0) { return (true); } /* We are manipulating the implementor tables of all implemented * interfaces. We must lock them. To avoid deadlock, lets lock * them in ascending order. */ ifcs = KMALLOC(clazz->total_interface_len * sizeof(Hjava_lang_Class*)); memcpy(ifcs, clazz->interfaces, clazz->total_interface_len * sizeof(Hjava_lang_Class*)); /* this is bubble-sort */ do { k = 0; for (j = 0; j < clazz->total_interface_len - 1; j++) { Hjava_lang_Class* iface_j = ifcs[j]; Hjava_lang_Class* iface_j1 = ifcs[j+1]; if ((uintp)iface_j > (uintp)iface_j1) { k = 1; ifcs[j] = iface_j1; ifcs[j+1] = iface_j; } } } while (k); for (j = 0; j < clazz->total_interface_len; j++) { lockClass(ifcs[j]); } i = 0; do { found_i = 1; for (j = 0; j < clazz->total_interface_len; j++) { Hjava_lang_Class* iface = clazz->interfaces[j]; uintp len = 0; if (iface->implementors != NULL) { /* This is how many entries follow, so the * array has a[0] + 1 elements. We have to convert * the value from pointer type (which is at least 16 bits * as previously). */ len = (uintp)iface->implementors[0]; } if (i >= len || iface->implementors[i+1] == NULL) { continue; /* this one would work */ } else { found_i = 0; break; } } i++; } while (!found_i); /* 'i' is a suitable index --- note we incremented i before leaving * the loop above. */ clazz->impl_index = i; /* Now patch all interfaces to point back to their itable2dtable * regions in the dispatch table of this implementing class. */ for (j = 0; j < clazz->total_interface_len; j++) { Hjava_lang_Class* iface = clazz->interfaces[j]; uintp len; /* make sure the implementor table is big enough */ if (iface->implementors == NULL || i > (uintp)iface->implementors[0]) { if (iface->implementors == NULL) { len = (i + 1) + 4; /* 4 is slack only */ iface->implementors = (void ***)gc_malloc(len * sizeof(void **), KGC_ALLOC_CLASSMISC); } else { /* double in size */ len = (uintp)(iface->implementors[0] + 1) * 2; if (len <= i) { len = (i + 1) + 4; } iface->implementors = (void ***)gc_realloc( iface->implementors, len * sizeof(void **), KGC_ALLOC_CLASSMISC); } if (iface->implementors == NULL) { postOutOfMemory(einfo); goto done; } /* NB: we assume KMALLOC/KREALLOC zero memory out */ iface->implementors[0] = (void *)(len - 1); /* New entries are magically marked as unused by the GC * as it fills the memory with 0. */ } assert(i < (uintp)iface->implementors[0] + 1); iface->implementors[i] = &(clazz->itable2dtable[clazz->if2itable[j]]); } rc = true;done: for (j = clazz->total_interface_len - 1; j >= 0; j--) { unlockClass(ifcs[j]); } KFREE(ifcs); return (rc);}/* Check for undefined abstract methods if class is not abstract. * See "Java Language Specification" (1996) section 12.3.2. * * Returns true if the class is abstract or if no abstract methods were * found, false otherwise. */staticboolcheckForAbstractMethods(Hjava_lang_Class* class, errorInfo *einfo){ int i; void **mtab = class->vtable->method; if ((class->accflags & ACC_ABSTRACT) == 0) { for (i = 0; i < class->msize; i++) { if (mtab[i] == NULL) { postException(einfo, JAVA_LANG(AbstractMethodError)); return (false); } } } return (true);}/* * This functions simply assign indices to the virtual methods in an * interface. * * In addition, if the interface has a <clinit> method, it builds a * trampoline for it. */staticbool/* ARGSUSED */prepareInterface(Hjava_lang_Class* class, errorInfo *einfo){ Method* meth; int i; meth = Kaffe_get_class_methods(class); class->msize = 0; /* enumerate indices and store them in meth->idx */ for (i = 0; i < CLASS_NMETHODS(class); i++, meth++) { if (meth->accflags & ACC_STATIC) { meth->idx = -1; /* Handle <clinit> */ if (utf8ConstEqual(meth->name, init_name)) { void **where; where = (void**)PMETHOD_NATIVECODE(meth); if (engine_buildTrampoline(meth, where, einfo) == 0) { return (false); } } } else { meth->idx = class->msize++; } } return (true);}/* * convert a CONSTANT_String entry in the constant poool * from utf8 to java.lang.String */Hjava_lang_String*resolveString(Hjava_lang_Class* clazz, int idx, errorInfo *info){ Utf8Const* utf8; Hjava_lang_String* str = NULL; constants* pool; pool = CLASS_CONSTANTS(clazz); lockClass(clazz); switch (pool->tags[idx]) { case CONSTANT_String: utf8 = WORD2UTF(pool->data[idx]); str = utf8Const2Java(utf8); if (!str) { postOutOfMemory(info); break; } pool->data[idx] = (ConstSlot)str; pool->tags[idx] = CONSTANT_ResolvedString; utf8ConstRelease(utf8); break; case CONSTANT_ResolvedString: /* somebody else resolved it */ str = (Hjava_lang_String*)pool->data[idx]; break; default: assert(!!!"Neither String nor ResolvedString?"); } unlockClass(clazz); return (str);}#undef EAGER_LOADING/* * Initialise the constants. * First we make sure all the constant strings are converted to java strings. * * This code removed: * There seems to be no need to be so eager in loading * referenced classes or even resolving strings. */staticboolresolveConstants(Hjava_lang_Class* class UNUSED, errorInfo *einfo UNUSED){ bool success = true;#ifdef EAGER_LOADING iLock* lock; int idx; constants* pool; Utf8Const* utf8; lockClass(class); /* Scan constant pool and convert any constant strings into true * java strings. */ pool = CLASS_CONSTANTS (class); for (idx = 0; idx < pool->size; idx++) { switch (pool->tags[idx]) { case CONSTANT_String: utf8 = WORD2UTF(pool->data[idx]); /* XXX: unchecked malloc */ pool->data[idx] = (ConstSlot)utf8Const2Java(utf8); pool->tags[idx] = CONSTANT_ResolvedString; utf8ConstRelease(utf8); break; case CONSTANT_Class: if (getClass(idx, class, einfo) == 0) { success = false; goto done; } break; } }done: unlockClass(this);#endif /* EAGER_LOADING */ return (success);}/* * Lookup a named field. Do not search super classes. Do not resolve the field. */static Field*lookupClassFieldLocal(Hjava_lang_Class* clp, Utf8Const* name, bool isStatic){ Field* fptr; int n; /* Search down class for field name */ if (isStatic) { fptr = CLASS_SFIELDS(clp); n = CLASS_NSFIELDS(clp); } else { fptr = CLASS_IFIELDS(clp); n = CLASS_NIFIELDS(clp); } while (--n >= 0) { if (utf8ConstEqual (name, fptr->name)) { return (fptr); } fptr++; } return (NULL);}/* * Lookup a named field. Search superclasses and resolve the field. */Field*lookupClassField(Hjava_lang_Class* clp, Utf8Const* name, bool isStatic, errorInfo *einfo){ Field *fptr; Hjava_lang_Class *c; for (c = clp; c; c = c->superclass) { fptr = lookupClassFieldLocal(c, name, isStatic); if (fptr) { /* Resolve field if necessary */ if (resolveFieldType(fptr, c, einfo) == 0) { return (NULL); } return (fptr); } } if (isStatic) { int i = clp->total_interface_len; Hjava_lang_Class **cp = &clp->interfaces[0]; while (--i >= 0) { fptr = lookupClassFieldLocal (*cp, name, true); if (fptr) { if (resolveFieldType(fptr, *cp, einfo) == 0) { return (NULL); } return (fptr); } cp++; } }DBG(RESERROR, dprintf("lookupClassField for %s failed %s:%s\n", isStatic?"static":"non-static",clp->name->data, name->data); ); postExceptionMessage(einfo, JAVA_LANG(NoSuchFieldError), "%s", name->data); return (NULL);}/* * Determine the number of arguments and return values from the * method signature. */voidcountInsAndOuts(const char* str, short* ins, short* outs, char* outtype){ *ins = sizeofSig(&str, false); *outtype = str[0]; *outs = sizeofSig(&str, false);}/* * Calculate size (in words) of a signature item. */intsizeofSigChar(char ch, bool want_wide_refs){ switch (ch) { case 'V': return 0; case 'I': case 'Z': case 'S': case 'B': case 'C': case 'F': return 1; break; case 'D': case 'J': return 2; break; case '[': case 'L': return want_wide_refs ? sizeof(void*) / sizeof(int32) : 1; default: break; } return -1;}/* * Calculate size (in words) of a signature item and move *strp so * that it points to the next element of the signature */intsizeofSigItem(const char** strp, bool want_wide_refs){ int count; const char* str; for (str = *strp; ; str++) { count = sizeofSigChar(*str, want_wide_refs); if (count == -1) { switch (*s
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?