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