📄 classresolver.c
字号:
/* * @(#)classresolver.c 1.19 02/09/27 * * Copyright 1995-1998 by Sun Microsystems, Inc., * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You * shall not disclose such Confidential Information and shall use * it only in accordance with the terms of the license agreement * you entered into with Sun. * Use is subject to license terms. *//*========================================================================= * SYSTEM: Verifier * SUBSYSTEM: class resolver.c. * FILE: classresolver.c * OVERVIEW: Routines for loading and resolving class definitions. * These routines should not be depending upon the interpreter * or the garbage collector. * AUTHOR: Sheng Liang, Sun Microsystems, Inc. * Modifications for CLDC compliance checks, * Tasneem Sayeed, Sun Microsystems * Frank Yellin, Sun Microsystems *=======================================================================*//*========================================================================= * Include files *=======================================================================*/#include <ctype.h>#include <string.h>#include <sys/types.h>#include <fcntl.h>#include <sys/stat.h>#include <stdlib.h>#include <oobj.h>#include <tree.h>#include <signature.h>#include <path.h>#include <sys_api.h>#include <convert_md.h>/*========================================================================= * Globals and extern declarations *=======================================================================*/ClassClass *classJavaLangObject;ClassClass *classJavaLangClass = 0;ClassClass *classJavaLangString;ClassClass *classJavaLangThrowable;ClassClass *classJavaLangError;ClassClass *classJavaLangException;ClassClass *classJavaLangRuntimeException;ClassClass *classJavaLangThreadDeath;ClassClass *interfaceJavaLangCloneable;ClassClass *interfaceJavaIoSerializable;bool_t inline_jsr_on = TRUE;static bool_t RunClinit(ClassClass * cb);static ClassClass *InitializeAndResolveClass(ClassClass *cb, bool_t resolve);static char *Locked_InitializeClass(ClassClass * cb, char **detail);static char *Locked_LinkClass(ClassClass * cb, char **detail);char * LinkClass(ClassClass *cb, char **detail);static ClassClass *FindLoadedClass(char *name, struct Hjava_lang_ClassLoader *loader);static ClassClass *Locked_FindArrayClassFromClass(struct execenv *ee, char *name, ClassClass *from);static void InitPrimitiveClasses();/* An Explanation of Class-related Locks * * There are two global locks related to class loading: * * LOADCLASS_LOCK: ensures that only one thread is loading a class at * a given time. This eliminates the possibility of two threads loading * classes with the same name and same loader. * * BINCLASS_LOCK: ensures that only one thread is updating the global * class table (binclasses). This lock is also grabbed by the GC to ensure * that the GC always sees a valid global class table state. * * In addition, each class may have its own associated locks that are * created with monitorEnter(). ResolveClass, for example, need to * first grab this lock to ensure that the class is resolved only by * one thread, rather than simultaneously by multiple threads. */sys_mon_t *_loadclass_lock;sys_mon_t *_binclass_lock;static struct fieldblock **addslots(struct fieldblock ** fb, ClassClass * cb){ long n = cbFieldsCount(cb); struct fieldblock *sfb = cbFields(cb); if (cbSuperclass(cb)) fb = addslots(fb, cbSuperclass(cb)); while (--n >= 0) { *fb++ = sfb; sfb++; } return fb;}intLocked_makeslottable(ClassClass * clb){ ClassClass *sclb; int nslots = 0; if (cbSlotTable(clb)) { return SYS_OK; } sclb = clb; while (sclb) { long n = cbFieldsCount(sclb); struct fieldblock *fb = cbFields(sclb); while (--n >= 0) { nslots++; fb++; } if (cbSuperclass(sclb) == 0) { break; } sclb = cbSuperclass(sclb); } cbSlotTableSize(clb) = nslots; if (nslots == 0) { nslots++; } cbSlotTable(clb) = (struct fieldblock **) sysMalloc(nslots * sizeof(struct fieldblock *)); if (cbSlotTable(clb) == 0) { return SYS_NOMEM; } addslots(cbSlotTable(clb), clb); return SYS_OK;}intmakeslottable(ClassClass * clb){ int result; LOADCLASS_LOCK(); result = Locked_makeslottable(clb); LOADCLASS_UNLOCK(); return result;}#if 0static char *copyclassname(char *src, char *dst){ sysAssert(*src == SIGNATURE_CLASS); src++; while (*src && *src != SIGNATURE_ENDCLASS) *dst++ = *src++; *dst = 0; return src;}#endifstatic char *ResolveFields(ClassClass *cb, unsigned slot){ struct fieldblock *fb; int size; fb = cbFields(cb); for (size = 0; size < (int) cbFieldsCount(cb); size++, fb++) { char *signature = fieldsig(fb); int size = (((signature[0] == SIGNATURE_LONG || signature[0] == SIGNATURE_DOUBLE)) ? 2 : 1); fb->ID = NameAndTypeToHash(fb->name, signature); if (fb->access & ACC_STATIC) { /* Do nothing. Handled when the class is loaded. */ } else { fb->u.offset = slot; slot += size * sizeof(OBJECT); }#ifdef UNUSED if ((fb->access & (ACC_STATIC | ACC_TRANSIENT)) == 0) { for (s = fieldname(fb); (c = *s++) != 0;) thishash = thishash * 7 + c; for (s = fieldsig(fb); (c = *s++) != 0;) thishash = thishash * 7 + c; }#endif } if (slot > 65535) { return "java/lang/InternalError"; } cbInstanceSize(cb) = slot;#ifdef UNUSED cbThisHash(cb) = thishash; if (cbSuperclass(cb)) cbTotalHash(cb) = thishash - cbTotalHash(unhand(cbSuperclass(cb))); else cbTotalHash(cb) = thishash; if (cbTotalHash(cb) < N_TYPECODES) cbTotalHash(cb) += N_TYPECODES;#endif return NULL;}static char *ResolveMethods(ClassClass *cb){ struct methodblock *mb; int size; struct methodtable *new_table; struct methodblock **super_methods; int mslot, super_methods_count; void *ptr; static unsigned finalizerID = 0; if (finalizerID == 0) finalizerID = NameAndTypeToHash(FINALIZER_METHOD_NAME, FINALIZER_METHOD_SIGNATURE); mb = cbMethods(cb); for (size = 0; size < (int) cbMethodsCount(cb); size++, mb++) { mb->fb.ID = NameAndTypeToHash(mb->fb.name, mb->fb.signature); mb->fb.u.offset = 0; mb->invoker = 0; } if (cbIsInterface(cb)) { /* We don't really need to built a method table for interfaces. */ cbMethodTable(cb) = NULL; cbMethodTableSize(cb) = 0; mb = cbMethods(cb); /* Each method's offset is its index in the interface */ for (size = 0; size < (int) cbMethodsCount(cb); size++, mb++) { mb->fb.u.offset = size; } return NULL; } if (cbSuperclass(cb) != NULL) { ClassClass *super = cbSuperclass(cb); mslot = cbMethodTableSize(super); super_methods = cbMethodTable(super)->methods; super_methods_count = cbMethodTableSize(super); /* Inherit one's parent's finalizer, if it has one */ cbFinalizer(cb) = cbFinalizer(cbSuperclass(cb)); } else { mslot = 1; super_methods = NULL; super_methods_count = 0; cbFinalizer(cb) = NULL; } mb = cbMethods(cb); for (size = 0; size < (int) cbMethodsCount(cb); size++, mb++) { unsigned long ID = mb->fb.ID; struct methodblock **super_methods_p; int count; if ((mb->fb.access & ACC_STATIC) || (mb->fb.access & ACC_PRIVATE)) continue; if (strcmp(mb->fb.name, "<init>") == 0) continue; /* If this item has its own finalizer method, grab it */ if (mb->fb.ID == finalizerID) { if (no_finalizers) { panic("finalize methods should not appear"); } cbFinalizer(cb) = mb; } for (super_methods_p = super_methods, count = super_methods_count; count > 0; super_methods_p++, count--) { if ((*super_methods_p != NULL) && ((*super_methods_p)->fb.ID == ID)) { /* Private methods are not inherited outside of the class. */ if ((*super_methods_p)->fb.access & ACC_PRIVATE) continue; /* Package-private methods are not inherited outside of the package. */ if (((*super_methods_p)->fb.access & ACC_PROTECTED) || ((*super_methods_p)->fb.access & ACC_PUBLIC) || IsSameClassPackage((*super_methods_p)->fb.clazz, cb)) { mb->fb.u.offset = (*super_methods_p)->fb.u.offset; break; } /* jio_fprintf(stderr, "!!!%s.%s\n", cbName(cb), mb->fb.name); */ } } if (mb->fb.u.offset == 0) { mb->fb.u.offset = mslot; mslot++; } } if (mslot > 65535) { return "java/lang/InternalError"; } /* * This should be the only place that method tables are * allocated. We allocate more than we need here and mask the * resulting pointer because the methodtable pointer field in * object handles is overloaded and sometimes hold array types * and array lengths. We must ensure that method table pointers * are allocated on an appropriate boundary so we don't lose any * address bits when we mask off the type portion of the pointer. */ ptr = sysMalloc(sizeof(struct methodtable) + (mslot - 1)* sizeof(struct methodblock *) + FLAG_MASK); if (ptr == NULL) { CCSet(cb, Error); return JAVAPKG "OutOfMemoryError"; } cbMethodTableMem(cb) = ptr; new_table = (struct methodtable *)((((long)ptr) + FLAG_MASK) & LENGTH_MASK); new_table->classdescriptor = cb; memset((char *)new_table->methods, 0, mslot * sizeof(struct methodblock *)); if (super_methods) memcpy((char *) new_table->methods, (char *) super_methods, super_methods_count * sizeof(struct methodblock *)); mb = cbMethods(cb); for (size = 0; size < (int) cbMethodsCount(cb); size++, mb++) { int offset = (int)mb->fb.u.offset; if (offset > 0) { sysAssert(offset < mslot); mt_slot(new_table, offset) = mb; } } cbMethodTable(cb) = new_table; cbMethodTableSize(cb) = mslot; return NULL;}static char *ResolveInterfaces(ClassClass *cb, char **detail){ const int ITEM_SIZE = sizeof(cbIntfMethodTable(cb)->itable[0]); bool_t isInterface = cbIsInterface(cb); if (cbImplementsCount(cb) == 0 && !isInterface) { /* classes that don't implement their own interfaces can just inherit * their parents imethodtable. */ if (cb == classJavaLangObject) { /* We can preinitialize the imethodtable of java.lang.Object */ static struct imethodtable t = { 0 }; cbIntfMethodTable(cb) = &t; } else { ClassClass *super = cbSuperclass(cb); cbIntfMethodTable(cb) = cbIntfMethodTable(super); } return NULL; } else { cp_item_type *constant_pool = cbConstantPool(cb); ClassClass *super = cbSuperclass(cb); unsigned char *mallocSpace, *mallocSpaceEnd; ClassClass *icb; /* temporary */ struct imethodtable *super_itable = cbIntfMethodTable(super); struct imethodtable *this_itable = NULL; int super_itable_count = super_itable->icount; int i, j, k, icount, mcount; /* Resolve all the interfaces that this class implements, and * make sure that they all really are interfaces * * icount will total all the interfaces that this class implements, * (include interfaces implemented by our superclass, and by * interfaces that we implement.) * mcount will total the total amount of space (in sizeof(long)) for * which we'll have to allocate space for in the offsets table. */ icount = super_itable_count + (isInterface ? 1 : 0); mcount = 0; for (i = 0; i < (int)(cbImplementsCount(cb)); i++) { int interface_index = cbImplements(cb)[i]; struct imethodtable *sub_itable; icb = constant_pool[interface_index].clazz; if (!cbIsInterface(icb)) { *detail = "Implementing class"; return JAVAPKG "IncompatibleClassChangeError"; } sub_itable = cbIntfMethodTable(icb); icount += sub_itable->icount; if (!isInterface) for (j = sub_itable->icount; --j >= 0; ) mcount += cbMethodsCount(sub_itable->itable[j].classdescriptor); } { int this_itable_size = offsetof(struct imethodtable, itable) + icount * ITEM_SIZE; int offsets_size = mcount * sizeof(unsigned long); mallocSpace = sysMalloc(this_itable_size + offsets_size); if (mallocSpace == NULL) { return JAVAPKG "OutOfMemoryError"; } mallocSpaceEnd = mallocSpace + this_itable_size + offsets_size; this_itable = (struct imethodtable *)mallocSpace; mallocSpace += this_itable_size; sysAssert(mallocSpace <= mallocSpaceEnd); } cbIntfMethodTable(cb) = this_itable; /* Start filling in the table. */ icount = 0; if (isInterface) { this_itable->itable[icount].classdescriptor = cb; this_itable->itable[icount].offsets = NULL; icount++; } if (super_itable_count > 0) { /* We can copy our superclass's offset table. The offsets will stay the same. */ memcpy(&this_itable->itable[icount], &super_itable->itable[0],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -