typeid.c

来自「This is a resource based on j2me embedde」· C语言 代码 · 共 2,203 行 · 第 1/5 页

C
2,203
字号
/* * @(#)typeid.c	1.114 06/10/10 * * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved.   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER   *    * This program is free software; you can redistribute it and/or   * modify it under the terms of the GNU General Public License version   * 2 only, as published by the Free Software Foundation.    *    * This program is distributed in the hope that it will be useful, but   * WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   * General Public License version 2 for more details (a copy is   * included at /legal/license.txt).    *    * You should have received a copy of the GNU General Public License   * version 2 along with this work; if not, write to the Free Software   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA   * 02110-1301 USA    *    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa   * Clara, CA 95054 or visit www.sun.com if you need additional   * information or have any questions.  * */#include "javavm/include/defs.h"#include "javavm/include/objects.h"#include "javavm/include/classes.h"#include "javavm/include/typeid.h"#include "javavm/include/typeid_impl.h"#include "javavm/include/globals.h"#include "javavm/include/signature.h"#include "javavm/include/utils.h"#include "javavm/include/common_exceptions.h"#include "javavm/include/preloader.h"#include "javavm/include/packages.h"#include "javavm/include/clib.h"#include "javavm/include/porting/system.h"#define isTableEntry( i ) (CVMtypeidIsBigArray(i)||(((i)>CVMtypeidLastScalar)&&(i)<(1<<CVMtypeidArrayShift)))/* * A limitation of the implementation * Since method sig table is private, no need to expose this. */#define CVM_TYPEID_MAX_SIG 0xfffe/************************************************************** * The same scheme of variable-length tables are used several * places: for memberNames, for both field and method types. * The same indexation idiom is used throughout. If this were Java * we'd use subclassing or something to share. Here, we use type casting. */struct genericTableHeader {    SEGMENT_HEADER( struct genericTableSegment )};struct genericTableSegment {    SEGMENT_HEADER( struct genericTableSegment )    char	genericData[1];};struct genericTableEntry {    COMMON_TYPE_ENTRY_HEADER};#ifdef CVM_DEBUGstatic struct idstat{    int nNamesAdded;    int nNamesDeleted;    int nClassesAdded;    int nClassesDeleted;    int nArraysAdded;    int nArraysDeleted;    int nPkgAdded;    int nPkgDeleted;    int nMethodSigsAdded;    int nMethodSigsDeleted;    int nMethodFormsAdded;    int nMethodFormsDeleted;    int nMethodDetailsAdded;    int nMethodDetailsDeleted;}idstat = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};static const char * const idstatName[] = {    "member names added:",    "           deleted:",    "  class id's added:",    "           deleted:",    "  array id's added:",    "           deleted:",    "    packages added:",    "           deleted:",    " method sigs added:",    "           deleted:",    "  terse sigs added:",    "           deleted:",    " sig details added:",    "           deleted:",    NULL};void CVMtypeidPrintStats(){    int i;    const char * name;    int * val = (int*)&idstat;    CVMconsolePrintf("Name and Type ID info changed:\n");    for ( i=0; (name = idstatName[i]) != NULL; i++ ){	CVMconsolePrintf("    %s %d\n", name, val[i]);    }    memset( &idstat, 0, sizeof(idstat));}#endifstatic void deletePackage( struct pkg * );static int getSignatureInfo( struct methodTypeTableEntry *mp, CVMUint32 **formp, CVMTypeIDTypePart** detailp );/* * We allocate segments bigger and bigger as we go. * Initial RAM allocation is modest. */#define INITIAL_SEGMENT_SIZE	1000#define ASSERT_LOCKED CVMassert(CVMreentrantMutexIAmOwner( (CVMgetEE()),  CVMsysMutexGetReentrantMutex(&CVMglobals.typeidLock)))/* * If we run out of memory or of table space, we want to throw an exception. * However, this can only be done with the typeidLock unlocked. Bracket the * throwing by conditional unlock/lock calls. They will usually be necessary. * (Also, since these errors seldom occur, we won't bother passing ee around just * for this case, but instead fetch it: locally more expensive, globally cheaper.) * OBVIOUSLY, make sure that the table is in a consistent state before unlocking! */static voidunlockThrowInternalError( const char * msg ){    CVMExecEnv * ee   = CVMgetEE();    CVMBool lockOwner = CVMsysMutexIAmOwner(ee, &CVMglobals.typeidLock );    if ( lockOwner ){	CVMsysMutexUnlock(ee, &CVMglobals.typeidLock );    }    CVMthrowInternalError( ee, msg );    if ( lockOwner ){	CVMsysMutexLock(ee, &CVMglobals.typeidLock );    }}static voidunlockThrowOutOfMemoryError(){    CVMExecEnv * ee   = CVMgetEE();    CVMBool lockOwner = CVMsysMutexIAmOwner(ee, &CVMglobals.typeidLock );    if ( lockOwner ){	CVMsysMutexUnlock(ee, &CVMglobals.typeidLock );    }    CVMthrowOutOfMemoryError( ee, NULL );    if ( lockOwner ){	CVMsysMutexLock(ee, &CVMglobals.typeidLock );    }}static voidunlockThrowNoClassDefFoundError(const char * name) {    CVMExecEnv * ee = CVMgetEE();    CVMBool lockOwner = CVMsysMutexIAmOwner(ee, &CVMglobals.typeidLock );    if ( lockOwner ) {        CVMsysMutexUnlock(ee, &CVMglobals.typeidLock );    }    CVMthrowNoClassDefFoundError( ee, name);    if ( lockOwner) {        CVMsysMutexLock(ee, &CVMglobals.typeidLock );    }}/* * Little routines used in all the ToCString routines, * in an attempt not to overrun externally-allocated buffers. * (This was a macro, but that seems the wrong space/time tradeoff.) */static void conditionalPutchar( char **chrp, int * lengthRemaining, char chr, CVMBool *success  ){    if ( *lengthRemaining > 1 ){ 	*(*chrp)++ = chr; 	*lengthRemaining -= 1;     } else { 	**chrp = '\0'; 	*success = CVM_FALSE; 	*lengthRemaining = 0;     }}static void conditionalPutstring(    char ** chrp, int * lengthRemaining, const char *string, int stringLength, CVMBool * success ){    int localLengthRemaining = *lengthRemaining;    if (localLengthRemaining <= 1) {	**chrp = '\0'; 	*success = CVM_FALSE; 	*lengthRemaining = 0; 	return;    }    if ( stringLength < localLengthRemaining ){	strncpy( *chrp, string, stringLength+1 );	*chrp += stringLength;	*lengthRemaining -= stringLength;    } else {	strncpy( *chrp, string, localLengthRemaining-1 );	*chrp += localLengthRemaining-1;	**chrp = '\0';	*success = CVM_FALSE;	*lengthRemaining = 0;    }}#define BASETYPE_CASES \	case CVM_TYPEID_VOID:  conditionalPutchar( &chp, &bufLength, 'V', &success ); break; \	case CVM_TYPEID_INT:   conditionalPutchar( &chp, &bufLength, 'I', &success ); break; \	case CVM_TYPEID_SHORT: conditionalPutchar( &chp, &bufLength, 'S', &success ); break; \	case CVM_TYPEID_CHAR:  conditionalPutchar( &chp, &bufLength, 'C', &success ); break; \	case CVM_TYPEID_LONG:  conditionalPutchar( &chp, &bufLength, 'J', &success ); break; \	case CVM_TYPEID_BYTE:  conditionalPutchar( &chp, &bufLength, 'B', &success ); break; \	case CVM_TYPEID_FLOAT: conditionalPutchar( &chp, &bufLength, 'F', &success ); break; \	case CVM_TYPEID_DOUBLE:conditionalPutchar( &chp, &bufLength, 'D', &success ); break; \	case CVM_TYPEID_BOOLEAN: conditionalPutchar( &chp, &bufLength, 'Z', &success ); break;/* * Initialize the type Id system * Register some well-known typeID's  */CVMBoolCVMtypeidInit( CVMExecEnv *ee ){    CVMglobals.typeIDscalarSegmentSize = INITIAL_SEGMENT_SIZE;    CVMglobals.typeIDmethodTypeSegmentSize = INITIAL_SEGMENT_SIZE;    CVMglobals.typeIDmemberNameSegmentSize = INITIAL_SEGMENT_SIZE;    CVMglobals.initTid = 	CVMtypeidLookupMethodIDFromNameAndSig(ee, "<init>", "()V");    CVMglobals.clinitTid = 	CVMtypeidLookupMethodIDFromNameAndSig(ee, "<clinit>", "()V");    CVMglobals.finalizeTid = 	CVMtypeidLookupMethodIDFromNameAndSig(ee, "finalize", "()V");    CVMglobals.cloneTid = 	CVMtypeidLookupMethodIDFromNameAndSig(ee, "clone", "()V");#ifdef CVM_DEBUG_STACKTRACES    CVMglobals.printlnTid =	CVMtypeidLookupMethodIDFromNameAndSig(ee, "println", 					   "(Ljava/lang/String;)V");#endif#ifdef CVM_DUAL_STACK    {        const char *midpImplLoaderName =             "sun/misc/MIDPImplementationClassLoader";        const char *midletLoaderName =             "sun/misc/MIDletClassLoader";        CVMglobals.midpImplClassLoaderTid = CVMtypeidNewClassID(            ee, midpImplLoaderName, strlen(midpImplLoaderName));        CVMglobals.midletClassLoaderTid = CVMtypeidNewClassID(            ee, midletLoaderName, strlen(midletLoaderName));        if (CVMglobals.midpImplClassLoaderTid == CVM_TYPEID_ERROR ||            CVMglobals.midletClassLoaderTid == CVM_TYPEID_ERROR) {            return CVM_FALSE;        }    }#endif    return CVM_TRUE;}/* * A second stage of type ID initialization. * Register all pre-loaded packages using * CVMpackagesAddPackageEntry( pkgName, strlen(pkgName), "<preloaded>" ) */extern voidCVMtypeidRegisterPreloadedPackages(){    struct pkg ** hashbucket;    struct pkg *  pkgp;    int i;    size_t maxLength = 0;    char * buffer;    for ( i = 1; i < NPACKAGEHASH; i++ ){	hashbucket = &CVM_pkgHashtable[ i ];	for ( pkgp = *hashbucket; pkgp != NULL; pkgp = pkgp->next ){	    size_t l = strlen( pkgp->pkgname );	    if ( l > maxLength ) maxLength = l;	}    }    buffer = (char *)malloc( maxLength + 2 );    if ( buffer == NULL ) return;    for ( i = 1; i < NPACKAGEHASH; i++ ){	hashbucket = &CVM_pkgHashtable[ i ];	for ( pkgp = *hashbucket; pkgp != NULL; pkgp = pkgp->next ){	    if ( pkgp->pkgname[0] != '\0' ){		size_t l = strlen( pkgp->pkgname );		strncpy( buffer, pkgp->pkgname, l );		buffer[l] = '/'; /* makes  CVMpackagesAddEntry happy */		buffer[l+1] = '\0';		CVMpackagesAddEntry( buffer, "<preloaded>" );	    }	}    }    free( buffer );}struct genericTableSegment;static void  processSegmentedTable(    struct genericTableSegment * thisSeg,     size_t			 entrySize,    void   (*entryCallback)(void*),    void   (*segmentCallback)(void*) );/* * Callbacks for giving back memory. */static void destroyScalarEntry( void * t ){    struct scalarTableEntry * p = (struct scalarTableEntry *)t;    if ( p->tag == CVM_TYPE_ENTRY_OBJ ){	free( (void*)(p->value.className.classInPackage) ); /*cast away const */	p->value.className.classInPackage = NULL;    }}static void destroyMemberName( void * t ){    struct memberName * p = (struct memberName*)t;    free( (void*)(p->name) ); /*cast away const*/    p->name = NULL;}static void destroySignature( void * t ){    struct methodTypeTableEntry * p = (struct methodTypeTableEntry*) t;    CVMTypeIDTypePart * detailp;    int nDetail;    nDetail = getSignatureInfo( p, NULL, &detailp );    if ( nDetail > N_METHOD_INLINE_DETAILS){	p->form.formp = NULL; /* dead for sure */	free( detailp );    }}static void destroySegment( void * ); /* see later *//* * Give back memory. Leaves a mess, as we don't * neatly unlink things! */voidCVMtypeidDestroy( ){    /*     * Destroy signatures first, as they depend     * on forms for interpretation. Then do other tables.     */    struct sigForm *thisSig, *nextSig;    struct pkg     *thisPkg, *nextPkg;    int i;    processSegmentedTable(	(struct genericTableSegment*)&CVMMethodTypeTable,	sizeof(struct methodTypeTableEntry),	destroySignature, destroySegment );    processSegmentedTable(	(struct genericTableSegment*)&CVMFieldTypeTable,	sizeof(struct scalarTableEntry),	destroyScalarEntry, destroySegment );    processSegmentedTable(	(struct genericTableSegment*)&CVMMemberNames,	sizeof(struct memberName),	destroyMemberName, destroySegment );    /*     * fields are on a single linked list.     * Assume that any with max ref count are in Rom.     */    nextSig = *CVMformTablePtr;    while ( nextSig != NULL && (nextSig->refCount) != MAX_COUNT ){	thisSig = nextSig;	nextSig = thisSig->next;	free( thisSig );    }    /*     * packages are on multiple lists. There is an INROM flag for them.     */    for ( i = 0 ; i < NPACKAGEHASH; i++ ){	nextPkg = CVM_pkgHashtable[i];	while ( nextPkg != NULL ){	    thisPkg = nextPkg;	    nextPkg = thisPkg->next;	    if ( thisPkg->state != TYPEID_STATE_INROM ){		free( thisPkg );	    }	}    }}/**************************************************************** * A simple name hashing function. * It is used in a bunch of places for turning names into numbers * It must be EXACTLY the same as the one used in JavaCodeCompact to * build the initial type tables, else we'll never find the entries! */static unsigned computeHash( const char * name, int l ){    /*     * Since suffix is more likely to be unique,     * hash from the back end.     */    const unsigned char * s = (const unsigned char *)name;    unsigned v = 0;    int n = ( l > 7 ) ? 7 : l;    s += l-n;    while ( n--> 0 ){	v = (v*19) + s[n] - '/';    }    return v;}static void  processTableSegment(    struct genericTableSegment * thisSeg,     size_t			 entrySize,    void   (*callback)(void*)){    int i, n;    char *   thisEntry;    n = thisSeg->nInSegment;    if ( thisSeg->nextFree >= 0 )	n = thisSeg->nextFree;    thisEntry = &(thisSeg->genericData[0]);    for ( i = 0; i < n; i++ ){#ifndef NO_RECYCLE	if ( ((struct genericTableEntry*)thisEntry)->refCount != 0 )#endif	    callback(thisEntry);	thisEntry += entrySize;    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?