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