jitcodebuffer.c

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

C
1,924
字号
/* * @(#)jitcodebuffer.c	1.102 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.  * *//* * Code buffer management. * The main code buffer has positive relative addresses. * Every "push" operation allocates a new buffer segment at a negative * address. "Pop" returns you to the previous buffer stream. * * Currently, push is limited to depth 4, simply so I can allocate a * fixed-size stack, and this seems quite adequate for allowing * exceptions within late bindings. Depth 2 should be adequate. * Currently all we really do is manipulate the logical PC, which is * used by the emitters and the fixup mechanism.  Obviously this * should be part of the compiler context, thus the "con" * parameters. But for now we don't even bother.   */#include "javavm/include/defs.h"#include "javavm/include/objects.h"#include "javavm/include/classes.h"#include "javavm/include/directmem.h"#include "javavm/include/utils.h"#include "javavm/include/bcutils.h"#include "javavm/include/jit/jit.h"#include "javavm/include/jit/jitir.h"#include "javavm/include/jit/jitcontext.h"#include "javavm/include/jit/jitirnode.h"#include "javavm/include/jit/jitirblock.h"#include "javavm/include/jit/jitcodebuffer.h"#include "javavm/include/jit/jitconstantpool.h"#include "javavm/include/jit/jitmemory.h"#include "javavm/include/porting/jit/jit.h"#include "javavm/include/porting/io.h"#ifdef CVM_JIT_PROFILE#include "javavm/include/porting/time.h"#endif/* * Data structure used to maintain lists of freed buffers. */struct CVMJITFreeBuf{    CVMUint32      size;    CVMJITFreeBuf* next;    CVMJITFreeBuf* prev;};typedef struct {    CVMUint32      size;    CVMUint32      cmdOffset;} CVMJITAllocedBuf;static voidCVMJITcodeCacheAddBufToFreeList(CVMUint8* cbuf);static voidCVMJITcodeCacheRemoveBufFromFreeList(CVMUint8* cbuf);static CVMUint8*CVMJITcodeCacheFindFreeBuffer(CVMJITCompilationContext* con,			      CVMUint32 bufSizeEstimate,			      CVMBool remove);static voidCVMJITcodeCacheMakeRoomForMethod(CVMJITCompilationContext* con,				 CVMUint32 bufSize);#define CVMJITcbufAlignAddress(addr) \    (CVMUint8*)(((CVMUint32)(addr) + 3) & ~3)/* * Called before we start to compile the method. */voidCVMJITcbufInitialize(CVMJITCompilationContext* con){    con->curDepth       = 0;    #ifdef CVM_DEBUG_ASSERTS    con->oolCurDepth    = -1;#endif        /* estimate */    con->numMainLineInstructionBytes  = 0;    con->numBarrierInstructionBytes = 0;    con->numVirtinlineBytes = 0;    con->numLargeOpcodeInstructionBytes = 0;        con->codeBufAddr  = NULL;        /*     * Try to make sure that there is enough memory in the code cache for     * the method. This will help prevent wasting time repeatedly trying     * to compile a method that won't fit in the code cache. Note that      * there is no guarantee that the size guess is big enough.     */    {	CVMUint32 bufSizeEstimate = CVMmbCodeLength(con->mb) * 8;	CVMUint8* cbuf = 	    CVMJITcodeCacheFindFreeBuffer(con, bufSizeEstimate, CVM_FALSE);	if (cbuf == NULL) {	    CVMJITcodeCacheMakeRoomForMethod(con, bufSizeEstimate);	}    }}#define CVMJITcbufSetCmd0(cbuf, _cmd)	\    ((CVMJITAllocedBuf *)(cbuf))->cmdOffset = (CVMUint32)(_cmd) - (CVMUint32)cbuf;void CVMJITcbufSetCmd(CVMUint8 *cbuf, CVMCompiledMethodDescriptor *cmd){    CVMJITcbufSetCmd0(cbuf, cmd);}/* * Allocate buffer and set pointers. Called just before we generate code. */voidCVMJITcbufAllocate(CVMJITCompilationContext* con, CVMSize extraSpace){    CVMJITGlobalState* jgs = &CVMglobals.jit;    CVMUint32 bufSizeEstimate;    CVMUint8* cbuf;    int extraExpansion = con->extraCodeExpansion;    con->numMainLineInstructionBytes = CVMCPU_ENTRY_EXIT_SIZE +       (con->codeLength * (CVMCPU_CODE_EXPANSION_FACTOR + extraExpansion));    bufSizeEstimate = CVMCPU_INITIAL_SIZE + 	con->numMainLineInstructionBytes +	con->numBarrierInstructionBytes +	con->numLargeOpcodeInstructionBytes +	con->numVirtinlineBytes;    /* Make room for CVMCompiledMethodDescriptor */    bufSizeEstimate += sizeof(CVMCompiledMethodDescriptor);    /* Make room for inliningInfo, gcCheckPcs, and pcMapTable */    if (extraSpace > 0) {	bufSizeEstimate += extraSpace;	bufSizeEstimate += sizeof (CVMUint32);    }    /* Make room for stackmaps */    bufSizeEstimate += con->extraStackmapSpace;    bufSizeEstimate = CVMpackSizeBy(bufSizeEstimate, 4);        if (bufSizeEstimate > 0xffff ||  	bufSizeEstimate > jgs->maxCompiledMethodSize)    {	const char formatStr[] =	    "Method is too big: estimated size=%d allowed=%d";	/* Max int is only 10 digits.  Allow 2 10-digit numbers for the sizes	   plus 1 char for '\0': */	int length = sizeof(formatStr) + 10 + 10 + 1;	char *msg = CVMJITmemNew(con, JIT_ALLOC_DEBUGGING, length);	CVMUint32 limit = 0xffff < jgs->maxCompiledMethodSize ?	                  0xffff : jgs->maxCompiledMethodSize;	sprintf(msg, formatStr, bufSizeEstimate, limit);	CVMJITlimitExceeded(con, msg);    }    /* Start with the last possible instruction in this buffer (sort of       like maxLogicalPC) */    con->earliestConstantRefPC = MAX_LOGICAL_PC;#ifdef CVM_JIT_USE_FP_HARDWARE        con->earliestFPConstantRefPC = MAX_LOGICAL_PC;#endif        /* find a free buffer to generate code into */    cbuf = CVMJITcodeCacheFindFreeBuffer(con, bufSizeEstimate, CVM_TRUE);#ifdef CVM_AOT    if (CVMglobals.jit.isPrecompiling) {        /* If we are doing AOT compilation, make sure the cbuf is         * allocated within the AOT code cache */        if (cbuf == NULL ||            (cbuf + bufSizeEstimate) > CVMglobals.jit.codeCacheAOTEnd) {            CVMconsolePrintf("WARNING: Code cache is full during AOT"                             "compilation. Please use a larger AOT "                             "code cache using -Xjit:aotCodeCacheSize=<size>.\n");            CVMabort();        }    }#endif    if (cbuf == NULL) {	/* Make sure there is enough memory in the code cache */	CVMJITcodeCacheMakeRoomForMethod(con, bufSizeEstimate);	/* Try again. This time it's guaranteed to succeed. */	cbuf = CVMJITcodeCacheFindFreeBuffer(con, bufSizeEstimate, CVM_TRUE);	CVMassert(cbuf != NULL);    }    con->codeBufAddr = cbuf;    /* Make sure codeBufEnd doesn't allow for a method that is too big. */    {	CVMUint32 cbufSize;	if (CVMJITcbufSize(cbuf) > jgs->maxCompiledMethodSize) {	    cbufSize = jgs->maxCompiledMethodSize;	} else {	    cbufSize = CVMJITcbufSize(cbuf);	}	/* Leave room for the size tag at the end of the buffer. */	con->codeBufEnd = cbuf + cbufSize - sizeof(CVMUint32);    }    /* Skip size header */    con->curPhysicalPC = (CVMUint8 *)&((CVMJITAllocedBuf *)cbuf)->cmdOffset;    /* CMD pointer */    CVMJITcbufSetCmd0(cbuf, 0);    con->curPhysicalPC += sizeof ((CVMJITAllocedBuf *)cbuf)->cmdOffset;    CVMtraceJITCodegenExec({        CVMconsolePrintf("NUM BARRIER BYTES = %d\n",                         con->numBarrierInstructionBytes);        CVMconsolePrintf("NUM VIRTUAL INLINE BYTES = %d\n",                         con->numVirtinlineBytes);        CVMconsolePrintf("NUM LARGE OPCODE BYTES = %d\n",                         con->numLargeOpcodeInstructionBytes);        CVMconsolePrintf("NUM MAIN LINE INSTRUCTION BYTES ESTIMATE = %d\n",                         con->numMainLineInstructionBytes);        CVMconsolePrintf("ESTIMATED BUFFER SIZE = %d\n",                         bufSizeEstimate);        CVMconsolePrintf("CODE BUFFER ADDRESS = 0x%x\n",                         con->codeBufAddr);    });}/* * Called when done compiling and we want to commit the code buffer. * Anything free space at the end of the code buffer is freed up. */voidCVMJITcbufCommit(CVMJITCompilationContext* con){    CVMUint8* cbuf = con->codeBufAddr;    CVMUint32 bufSize;    CVMUint32 origBufSize = CVMJITcbufSize(cbuf);    CVMUint8* cbufEnd;    con->curPhysicalPC += sizeof(CVMUint32); /* adjust for size field at end */    con->curLogicalPC  += sizeof(CVMUint32); /* adjust for size field at end */    cbufEnd = CVMJITcbufAlignAddress(con->curPhysicalPC);    bufSize = cbufEnd - cbuf;        CVMassert(CVMsysMutexIAmOwner(con->ee, &CVMglobals.jitLock));        /* If there is enough extra at the end of this buffer, then free it */    if (origBufSize - bufSize >= sizeof(CVMJITFreeBuf) + sizeof(CVMUint32)) {	CVMUint8* freeBuf = cbuf + bufSize;	CVMJITcbufSetCommittedBufSize(cbuf, bufSize); /* commit the buffer */	CVMJITcbufSetUncommitedBufSize(freeBuf, origBufSize - bufSize);	CVMJITcbufFree(freeBuf, CVM_FALSE);    } else {	bufSize = origBufSize;	CVMJITcbufSetCommittedBufSize(cbuf, bufSize); /* commit the buffer */    }#ifdef CVM_AOT    if (CVMglobals.jit.isPrecompiling) {        /* If we are doing AOT compilation, make sure the cbuf is         * allocated within the AOT code cache */        if ((cbuf + CVMJITcbufSize(cbuf)) > CVMglobals.jit.codeCacheAOTEnd) {            CVMconsolePrintf("WARNING: Code cache is full during AOT"                             "compilation. Please use a larger AOT "                             "code cache using-Xjit:aotCodeCacheSize=<size>.\n");            CVMabort();        }    }#endif    /* Update the total bytes of the cache that are allocated */    CVMglobals.jit.codeCacheBytesAllocated += CVMJITcbufSize(cbuf);#if 0    CVMtraceJITStatus(("JS: Allocated(%d) - code cache now %d%% full\n",		       CVMJITcbufSize(cbuf),		       (CVMglobals.jit.codeCacheBytesAllocated * 100 /			CVMglobals.jit.codeCacheSize)));#endif#ifdef CVM_JIT_COLLECT_STATS    /* Keeps stats gathering from thinking we wasted a bunch */    con->codeBufEnd = cbuf + bufSize;#endif}static voidCVMJITsetCodeCacheDecompileStart(CVMUint8 *p){    CVMglobals.jit.codeCacheDecompileStart = p;    /* If the start of the allowable decompilation region gets moved, then       we must make sure that the next decompilation scan does not start       before this allowed region: */    if (CVMglobals.jit.codeCacheNextDecompileScanStart < p) {        CVMglobals.jit.codeCacheNextDecompileScanStart = p;   }#if 0    TRACE_RECORD_REGION("Decompile Space",	p,	CVMglobals.jit.codeCacheEnd);#endif}voidCVMJITmarkCodeBuffer(){    /* Locking? */#ifdef CVM_AOT    if (!CVMglobals.jit.codeCacheAOTCodeExist)#endif    {        if (CVMglobals.jit.codeCacheFirstFreeBuf != NULL) {            CVMJITsetCodeCacheDecompileStart(                (CVMUint8*)CVMglobals.jit.codeCacheFirstFreeBuf);        } else {            CVMJITsetCodeCacheDecompileStart(                CVMglobals.jit.codeCacheEnd);        }    }#ifdef CVM_USE_MEM_MGR    {	/* shared codecache */	CVMmemRegisterCodeCache();    }#endif /* CVM_USE_MEM_MGR */#ifdef CVM_AOT    /* We are done AOT compilation. All methods compiled after this     * point will not saved as AOT code.     */    CVMJITcodeCachePersist(&CVMglobals.jit);#ifndef CVM_MTASK    /* If CVM_MTASK is enabled, isPrecompiling is set to     * false in the child VM.     */    CVMglobals.jit.isPrecompiling = CVM_FALSE;#endif#endif}/* * Called to free a buffer. "committed" is a flag that indicates if * CVMJITcbufCommit() has been called on the buffer or not. */voidCVMJITcbufFree(CVMUint8* cbuf, CVMBool committed) {    CVMUint32 cbufSize = CVMJITcbufSize(cbuf);    CVMJITGlobalState* jgs = &CVMglobals.jit;    /*     * Only adjust bytes allocated if CVMJITcbufCommit() was called     * on this buffer.     */    if (committed) {	jgs->codeCacheBytesAllocated -= cbufSize;    }#if 0    CVMtraceJITStatus(("JS: Free(%d) - code cache now %d%% full\n",		       cbufSize,		       (jgs->codeCacheBytesAllocated * 100 /			jgs->codeCacheSize)));#endif    /* Merge with next buffer if it is free */    {	CVMUint8* nextBuf = CVMJITcbufNextBuf(cbuf);	if (nextBuf != jgs->codeCacheEnd) {	    if (CVMJITcbufIsFree(nextBuf)) {		CVMJITcodeCacheRemoveBufFromFreeList(nextBuf);		cbufSize += CVMJITcbufSize(nextBuf);	    }	}    }    /* Merge with previous buffer if it is free */    if (cbuf != jgs->codeCacheStart) {	CVMUint8* prevBuf = CVMJITcbufPrevBuf(cbuf);	if (CVMJITcbufIsFree(prevBuf)) {	    /* Fixup codeCacheDecompileStart if necessary. This can only	     * happen because of class unloading or shutdown. */	    if (cbuf == jgs->codeCacheDecompileStart) {		CVMdebugPrintf(("WARNING: codeCacheDecompileStart lowered\n"));		CVMJITsetCodeCacheDecompileStart(prevBuf);	    }	    CVMJITcodeCacheRemoveBufFromFreeList(prevBuf);	    cbufSize += CVMJITcbufSize(prevBuf);	    cbuf = prevBuf;	}    }    /* Add the buffer to the free list. */    CVMJITcbufSetFreeBufSize(cbuf, cbufSize);    CVMJITcodeCacheAddBufToFreeList(cbuf);    /* Start the next decompilation scan after this freed buffer so as to       avoid immediately decompiling the method which may immediately       be compiled into this freed buffer. */    jgs->codeCacheNextDecompileScanStart = cbuf + CVMJITcbufSize(cbuf);    /* Make sure we don't start at the end of the codeCache next time.  If       we're pointing to the end of the codeCache, then change it to point       to the start: */    if (jgs->codeCacheNextDecompileScanStart == jgs->codeCacheEnd) {	jgs->codeCacheNextDecompileScanStart =	    jgs->codeCacheDecompileStart;    }}/* * Allow re-emit fixups. */voidCVMJITcbufPushFixup(CVMJITCompilationContext* con, CVMInt32 fixupPC){    CVMassert(con->curDepth<4);    /* Push context and re-map to out-of-line space */    con->logicalPCstack[con->curDepth++] = con->curLogicalPC;    con->curLogicalPC = fixupPC;    con->curPhysicalPC = CVMJITcbufLogicalToPhysical(con, fixupPC);#ifdef CVM_DEBUG_ASSERTS    /* This is not for OOL code, so the bounds are the same as before: */    {        CVMUint8* endBound;        if (con->oolCurDepth >= 0) {            endBound = con->oolPhysicalEndPCstack[con->oolCurDepth];        } else {            endBound = con->codeBufEnd;        }        con->oolCurDepth++;        CVMassert(con->oolCurDepth<4);        con->oolPhysicalStartPCstack[con->oolCurDepth] = con->curPhysicalPC;        con->oolPhysicalEndPCstack[con->oolCurDepth] = endBound;    }#endif    /* Make sure we don't push out of bounds */    CVMassert(con->curPhysicalPC >= con->codeBufAddr);    CVMtraceJITCodegen((">>>>>>>>>Push Code Buffer to PC = %d (0x%x) "                        ">>>>>>>>\n", con->curLogicalPC, con->curPhysicalPC));}extern void

⌨️ 快捷键说明

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