loadercache.c

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

C
1,232
字号
/* * @(#)loadercache.c	1.46 06/10/25 * * 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.  * *//* * Routines for maintaining the loader cache and loader constraints. */#include "javavm/include/defs.h"#include "javavm/include/objects.h"#include "javavm/include/classes.h"#include "javavm/include/globals.h"#include "javavm/include/utils.h"#include "javavm/include/directmem.h"#include "javavm/include/indirectmem.h"#include "javavm/include/globalroots.h"#include "javavm/include/common_exceptions.h"#ifdef CVM_CLASSLOADING#include "generated/offsets/java_lang_ClassLoader.h"#endif/* * For a complete description of class loader constraints and loader * cache, see the following paper: * *     "Dynamic Class Loading in the Java Virtual Machine" * * by Sheng Liang and Gilad Bracha. The paper will be published in the * proceedings of the OOPSLA'98 conference. *//*  * The Loader cache keeps a "(classID, loader) => cb" mapping. All the * classes in the cache have been verified to meet the class loader * constraints. The cache also speeds up class loading. * * Note that in the "(classID, loader) => cb" maping, "loader" is the * initiating loader, not necessary the loader that ultimately defines  * the class. A class loader may delegate class loading to another  * class loader. For example, when "java/lang/String" is loaded with  * an applet class loader, the resulting class in fact has NULL as its  * class loader. However, a loaded class will also always get an * entry with its actual class loader. * * When a new class is about to be added to the cache, we make sure  * it doesn't break any of the existing constraints. * * During the course of execution, new constraints may be added as * the result of class linking. Before each new constraint is added, * we make sure classes loaded in the cache will satisfy the new  * constraint. */struct CVMLoaderCacheEntry {    CVMLoaderCacheEntry* next;      /* next entry in hash bucket */    CVMClassBlock*       cb;    CVMClassLoaderICell* loader;    /* initiating loader */    int num_pds;    CVMObjectICell**     pds;       /* protection domains */};/* %comment c015 */#define CVM_LOADER_CACHE_TABLE_SIZE 1009#undef HASH_INDEX/*  *爈oader is casted to a native pointer (CVMClassLoaderICell*) * therefore the cast has to be CVMAddr which is 4 byte on * 32 bit platforms and 8 byte on 64 bit platforms * * ...but on the other hand we finally need an integer between 0 * and CVM_LOADER_CACHE_TABLE_SIZE. So it's quite safe to do only * an intermediate cast to CVMAddr to make the 64 bit compiler happy. */#define HASH_INDEX(classID, loader) \    (((CVMUint32)classID + (CVMUint32)(CVMAddr)loader) % CVM_LOADER_CACHE_TABLE_SIZE)/* * Loader constraints form a "(ClassTypeID, loader set) => cb" * mapping. * * The following structure stores an ClassTypeID and a set of loaders. * The loaders are required to map the ClassTypeID to the same cb. * * The cb field exists to speed up checking. It is initially set to  * NULL, and later set to the first class loaded by one of the  * loaders. *//* * Loader constraints aren't needed if we don't support class loading * or if class loaders are trusted. */#if defined(CVM_CLASSLOADING) && !defined(CVM_TRUSTED_CLASSLOADERS)struct CVMLoaderConstraint {    CVMLoaderConstraint* next;    CVMClassBlock*       cb;	/* initially NULL */    CVMClassTypeID       classID;    int num_loaders;            /* number of loaders[] entries in use */    int max_loaders;		/* capacity loaders[] */    CVMClassLoaderICell* loaders[2];	/* initiating loaders */};#define CVM_LOADER_CONSTRAINT_TABLE_SIZE 107/* * Return the loader constraint with the specified classID and loader. */static CVMLoaderConstraint**CVMloaderConstraintLookup(CVMClassTypeID classID, CVMClassLoaderICell* loader){    int index = (CVMUint32)classID % CVM_LOADER_CONSTRAINT_TABLE_SIZE;    CVMLoaderConstraint** pp = &CVMglobals.loaderConstraints[index];    while (*pp != NULL) {        CVMLoaderConstraint* p = *pp;	if (CVMtypeidIsSameType(p->classID, classID)) {	    int i;	    for (i = p->num_loaders - 1; i >= 0; i--) {	        if (p->loaders[i] == loader) {		    return pp;		}	    }	}	pp = &(p->next);    }    return pp;}/* * Make sure that the specified loader constraint has the specified  * number of free slots in the loaders[] array. */static CVMBoolCVMloaderConstraintEnsureCapacity(CVMExecEnv* ee,				  CVMLoaderConstraint** pp, int nfree){    CVMLoaderConstraint* p = *pp;    CVMLoaderConstraint* oldp;    if (p->max_loaders - p->num_loaders < nfree) {        int nh = offsetof(CVMLoaderConstraint, loaders);        int n = nfree + p->num_loaders;	if (n < 2 * p->max_loaders) {	    n = 2 * p->max_loaders;	}        p = (CVMLoaderConstraint *)malloc(nh + sizeof(void*) * n);	if (p == NULL) {	    return CVM_FALSE;	}	memcpy(p, *pp, nh + sizeof(void*) * (*pp)->num_loaders);	p->max_loaders = n;	/*	 * CVMloaderConstraintsMarkUnscannedClassesAndLoaders() may be	 * running and it doesn't grab the loaderCache lock, so we make	 * sure we block until it is done before we modify the entry.	 */	CVMD_gcUnsafeExec(ee, {	    oldp = *pp;	    *pp = p;	});	free(oldp);    }    return CVM_TRUE;}/* * Add the specified loader and cb to the specified loader constraint. */static CVMBoolCVMloaderConstraintExtend(CVMExecEnv* ee,			  CVMLoaderConstraint** pp, 			  CVMClassLoaderICell* loader,			  CVMClassBlock* cb){    if (!CVMloaderConstraintEnsureCapacity(ee, pp, 1)) {        return CVM_FALSE;    }    (*pp)->loaders[(*pp)->num_loaders++] = loader;    (*pp)->cb = cb;    return CVM_TRUE;}/* * Merge the two specified loader constraints into one. */static CVMBoolCVMloaderConstraintMerge(CVMExecEnv* ee,			 CVMLoaderConstraint **pp1,			 CVMLoaderConstraint **pp2,			 CVMClassBlock* cb){    CVMLoaderConstraint* p1;    CVMLoaderConstraint* p2;    int i;    /* make sure *pp1 has higher capacity */    if ((*pp1)->max_loaders < (*pp2)->max_loaders) {        CVMLoaderConstraint** tmp = pp2;	pp2 = pp1;	pp1 = tmp;    }    p1 = *pp1;    p2 = *pp2;        if (!CVMloaderConstraintEnsureCapacity(ee, pp1, p2->num_loaders)) {        return CVM_FALSE;    }    /*     * CVMloaderConstraintsMarkUnscannedClassesAndLoaders() may be     * running and it doesn't grab the loaderCache lock, so we make     * sure we block until it is done, so it doesn't look at this     * entry while it is being modified.     */    CVMD_gcUnsafeExec(ee, {	if (*pp1 != p1) {	    /* p1 has been moved */	    if (pp2 == &p1->next) {		/* need to update pp2 because p1 has moved */		pp2 = &(*pp1)->next;		p2 = *pp2;	    }	    p1 = *pp1;	} 	for (i = 0; i < p2->num_loaders; i++) {	    p1->loaders[p1->num_loaders++] = p2->loaders[i];	}	p1->cb = cb;	/* release pp2 */	*pp2 = p2->next;    });    free(p2);    return CVM_TRUE;}/*  * Impose a new loader constraint: "classID" must be loaded the same * way in loader1 and loader2. */static CVMBool CVMloaderConstraintAdd(CVMExecEnv* ee,		       CVMClassTypeID classID,		       CVMClassLoaderICell* loader1,		       CVMClassLoaderICell* loader2){    CVMLoaderConstraint** pp1;    CVMLoaderConstraint** pp2;    CVMClassBlock* cb;    CVMClassBlock* cb1;    CVMClassBlock* cb2;    CVMBool result;        CVM_LOADERCACHE_LOCK(ee);        /*     * See if either loader put the class in the loader cache. If they     * both did, then they both better have added the same class.     */    cb1 = CVMloaderCacheLookup(ee, classID, loader1);    cb2 = CVMloaderCacheLookup(ee, classID, loader2);    if (cb1 != NULL && cb2 != NULL && cb1 != cb2) {        goto constraint_violation;    } else {        cb = (cb1 != NULL ? cb1 : cb2);    }    /* Verify that we meet any constraint setup for <classID, loader1> */    pp1 = CVMloaderConstraintLookup(classID, loader1);    if (*pp1 != NULL && (*pp1)->cb != NULL) {        if (cb != NULL) {	    if (cb != (*pp1)->cb) {	        goto constraint_violation;	    }        } else {	    cb = (*pp1)->cb;        }    }    /* Verify that we meet any constraint setup for <classID, loader2> */    pp2 = CVMloaderConstraintLookup(classID, loader2);    if (*pp2 != NULL && (*pp2)->cb != NULL) {        if (cb != NULL) {	    if (cb != (*pp2)->cb) {	        goto constraint_violation;	    }        } else {	    cb = (*pp2)->cb;        }    }        /* If there is are not existing constraints, then make one. */    if (*pp1 == NULL && *pp2 == NULL) {        int index;        CVMLoaderConstraint* p =	    (CVMLoaderConstraint *)malloc(sizeof(CVMLoaderConstraint));	if (p == NULL) {	    result = CVM_FALSE;	} else {	    CVMtraceClassLoading(("LC: creating new constraint: "				  "0x%x => (0x%x, 0x%x, %!C)\n", 				  p, loader1, loader2, classID));		    p->classID = classID;	    p->loaders[0] = loader1;	    p->loaders[1] = loader2;	    p->num_loaders = 2;	    p->max_loaders = 2;	    p->cb = cb;	    	    index = (CVMUint32)classID % CVM_LOADER_CONSTRAINT_TABLE_SIZE;	    p->next = CVMglobals.loaderConstraints[index];	    CVMglobals.loaderConstraints[index] = p;	    result = CVM_TRUE;	}    } else if (*pp1 == *pp2) {        /* constraint already imposed */        (*pp1)->cb = cb;	result = CVM_TRUE;    } else if (*pp1 == NULL) {	/* failure implies OutOfMemoryError */        result = CVMloaderConstraintExtend(ee, pp2, loader1, cb);    } else if (*pp2 == NULL) { 	/* failure implies OutOfMemoryError */	result = CVMloaderConstraintExtend(ee, pp1, loader2, cb);    } else {	/* failure implies OutOfMemoryError */	result = CVMloaderConstraintMerge(ee, pp1, pp2, cb);    }    CVM_LOADERCACHE_UNLOCK(ee);    if (!result) {	CVMthrowOutOfMemoryError(ee, NULL);    }    return result;     constraint_violation:    CVM_LOADERCACHE_UNLOCK(ee);    CVMthrowLinkageError(ee, "Class %!C violates loader constraints", classID);    return CVM_FALSE;}/*  * Make sure all class components (including arrays) in the given * signature will be resolved to the same class in both loaders. * loader1 and loader2 must both be ClassLoader global roots. In other * words, they should orginate from the CVMcbClassLoader() field. */CVMBool CVMloaderConstraintsCheckMethodSignatureLoaders(CVMExecEnv* ee,						CVMMethodTypeID methodID, 						CVMClassLoaderICell* loader1,						CVMClassLoaderICell* loader2){    CVMClassTypeID argClassID;    CVMSigIterator sigIterator;    /* Nothing to do if loaders are the same. */    if (loader1 == loader2) {       return CVM_TRUE;    }    /* Handle the signature result type first */    CVMtypeidGetSignatureIterator(methodID, &sigIterator);    argClassID = CVM_SIGNATURE_ITER_RETURNTYPE(sigIterator);    /*     * Iteratate over all method argument types. The result type will     * be handled first.     */    do {	if (!CVMtypeidIsPrimitive(argClassID)) {	    if (!CVMloaderConstraintAdd(ee, argClassID, loader1, loader2)) {		return CVM_FALSE; /* exception already thrown */	    }	}	    	/* Get the next signature argument */

⌨️ 快捷键说明

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