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