jitcompile.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,252 行 · 第 1/3 页
C
1,252 行
CVMassert(offsetof(CVMJITUnaryOp, operand) == offsetof(CVMJITGenericSubNode, firstOperand));}#endifstatic voidbackOff(CVMMethodBlock* mb, CVMUint32 newInvokeCost){ /* Try again later. */ CVMUint32 oldInvokeCost = CVMmbInvokeCost(mb); if (newInvokeCost > CVMJIT_MAX_INVOKE_COST) { newInvokeCost = CVMJIT_MAX_INVOKE_COST; } if (newInvokeCost > oldInvokeCost) { CVMmbInvokeCostSet(mb, newInvokeCost); }}/* * Entry point to compiler */CVMJITReturnValueCVMJITcompileMethod(CVMExecEnv *ee, CVMMethodBlock* mb){ CVMJITCompilationContext con; CVMJITReturnValue retVal; volatile CVMBool needDestroyContext = CVM_FALSE; volatile int extraCodeExpansion = 0; volatile int extraStackmapSpace = 0; volatile int maxAllowedInliningDepth = CVMglobals.jit.maxAllowedInliningDepth; /* Cache the ee's noOSRSkip & noOSRStackAdjust in case we recurse into the interpreter while compiling: */ CVMInt32 noOSRSkip = ee->noOSRSkip; CVMInt8 noOSRStackAdjust = ee->noOSRStackAdjust;#ifdef CVM_JIT_COLLECT_STATS CVMInt64 startTime; CVMInt64 endTime;#endif#ifdef CVM_JIT_ESTIMATE_COMPILATION_SPEED static CVMInt32 measuredCycle; static CVMInt64 measuredStartTime;#endif CVMtraceJITAny(("JS: ATTEMPTING TO COMPILE %C.%M\n", CVMmbClassBlock(mb), mb)); CVMassert(CVMD_isgcSafe(ee)); /* * Check if this thread has been prohibited from doing compilations * in order to avoid a deadlock with the jitLock. */ if (ee->noCompilations) { return CVMJIT_CANNOT_COMPILE_NOW; } CVMJITstatsExec({ startTime = CVMtimeMillis(); }); /* One compilation at a time. Lock others out. */ CVMsysMutexLock(ee, &CVMglobals.jitLock); /* * Recursive entry into compiler should not happen! */ CVMassert(!CVMglobals.jit.compiling); CVMglobals.jit.compiling = CVM_TRUE;#ifdef CVM_JIT_ESTIMATE_COMPILATION_SPEED measuredCycle = CVMglobals.jit.doCSpeedMeasurement ? CVMJIT_NUMBER_OF_COMPILATION_PASS_MEASUREMENT_REPETITIONS : 1; measuredStartTime = CVMtimeMillis();#endif CVMglobals.jit.compilationAttempts++;#ifdef CVM_JIT_DEBUG CVMJITdebugInitCompilation(ee, mb);#endif#ifdef CVM_AOT /* AOT requires ROMization. If we are doing AOT compilation, * we better make sure the method is a ROMized method. */ if (CVMglobals.jit.isPrecompiling) { if (!CVMcbIsInROM(CVMmbClassBlock(mb))) { CVMconsolePrintf("CANNOT AOT NON-ROMIZED %C.%M\n", CVMmbClassBlock(mb), mb); CVMglobals.jit.aotCompileFailed = CVM_TRUE; retVal = CVMJIT_SUCCESS; goto done; } }#endif#ifdef CVM_JVMTI if (CVMjvmtiIsInDebugMode()) { retVal = CVMJIT_CANNOT_COMPILE; CVMJITsetErrorMessage(&con, "Debugger connected"); goto done; }#endif /* Check if mb is not compilable */ if (isBadMethod(ee, mb)) { retVal = CVMJIT_CANNOT_COMPILE; CVMJITsetErrorMessage(&con, "Method already marked as not compilable"); goto done; } /* Make sure the method isn't already compiled. */ if (CVMmbIsCompiled(mb)) { CVMtraceJITStatus(("JS: ALREADY COMPILED %C.%M\n", CVMmbClassBlock(mb), mb)); retVal = CVMJIT_SUCCESS; goto done; } CVMtraceJITAny(("JS: COMPILING %C.%M\n", CVMmbClassBlock(mb), mb)); retry: if (!CVMJITinitializeContext(&con, mb, ee, maxAllowedInliningDepth)) { CVMJITsetErrorMessage(&con, "Could not initialize compilation context"); retVal = CVMJIT_OUT_OF_MEMORY; goto done; } needDestroyContext = CVM_TRUE; if (setjmp(con.errorHandlerContext) == 0) { CVMJITinitializeCompilation(&con); CVMJITcompileBytecodeToIR(&con); /* Sanity check capacity */ CVMassert(con.capacity >= CVMjmdCapacity(con.jmd)); /* Sanity check code length */ CVMassert(con.codeLength >= CVMjmdCodeLength(con.jmd)); CVMJITcompileOptimizeIR(&con); con.extraCodeExpansion = extraCodeExpansion; con.extraStackmapSpace = extraStackmapSpace; CVMJITcompileGenerateCode(&con); CVMJITwriteStackmaps(&con);#ifdef CVM_JIT_PATCHED_METHOD_INVOCATIONS if (con.callees != NULL && (CVMUint32)con.callees[0] != 0) { /* Make room for the callee table. It will be after the stackmaps, which are located after the generated code. */ CVMUint32 numCallees = (CVMUint32)con.callees[0]; /* On platforms with variably sized instructions, such as x86, need to pad the codebuffer before the start of callee table. */ CVMMethodBlock** callees = (CVMMethodBlock**) (((CVMAddr)CVMJITcbufGetPhysicalPC(&con) + sizeof(CVMAddr) - 1) & ~(sizeof(CVMAddr) - 1)); CVMassert(CVMglobals.jit.pmiEnabled); CVMJITcbufGetPhysicalPC(&con) = (CVMUint8*)&callees[numCallees + 1]; if (CVMJITcbufGetPhysicalPC(&con) >= con.codeBufEnd) { /* Fail to compile. We will retry with a larger buffer */ CVMJITerror(&con, CODEBUFFER_TOO_SMALL, "Estimated code buffer too small"); } memcpy(callees, con.callees, (numCallees + 1) * sizeof(CVMMethodBlock*)); con.callees = callees; } else { con.callees = NULL; }#endif#ifdef CVM_JIT_ESTIMATE_COMPILATION_SPEED if (--measuredCycle != 0) { CVMJITerror(&con, RETRY, "Retry to measure compilation time"); }#endif /* By now, we know exactly the number of the maximum Temp words * (maxTempWords) of the compiled method. Before we go * any further, make sure it doesn't exceed 255 (0xFF) limit. */ if (con.maxTempWords > 0xFF) { CVMJITerror(&con, CANNOT_COMPILE, "Too many temp words (> 255)"); } /* No more errors allowed after this point */ { CVMUint8 *startPC = con.codeEntry; CVMCompiledMethodDescriptor *cmd = ((CVMCompiledMethodDescriptor *)startPC) - 1; CVMassert(con.mapPcNodeCount == 0 || con.pcMapTable->numEntries == con.mapPcNodeCount); CVMJITcbufSetCmd(con.codeBufAddr, cmd);#ifdef CVM_DEBUG_ASSERTS cmd->magic = CVMJIT_CMD_MAGIC;#endif CVMcmdSpillSize(cmd) = con.maxTempWords; CVMcmdCapacity(cmd) = con.capacity + CVMcmdSpillSize(cmd); CVMcmdMaxLocals(cmd) = con.numberLocalWords; CVMassert(CVMcmdStartPC(cmd) == con.codeEntry); { CVMUint8 *interpStartPC = startPC + con.intToCompOffset; cmd->startPCFromInterpretedOffsetX = interpStartPC - (CVMUint8 *)cmd; CVMassert(CVMcmdStartPCFromInterpreted(cmd) == interpStartPC); } /* We allocate memory in the code cache for other data, not just the compiled code. These regions are: PC map table, inlining info, gc patches, stackmaps, and callee table. */ /* Fill in the offsets for reaching our memory regions from the cmd */ cmd->codeBufOffsetX = (CVMUint16 *)con.codeBufAddr - (CVMUint16 *)cmd; CVMassert(CVMcmdCodeBufAddr(cmd) == con.codeBufAddr); cmd->pcMapTableOffsetX = (CVMUint16 *)con.pcMapTable - (CVMUint16 *)cmd; CVMassert(CVMcmdCompiledPcMapTable(cmd) == con.pcMapTable); if (con.stackmaps != NULL) { cmd->stackMapsOffsetX = (CVMUint16 *)con.stackmaps - (CVMUint16 *)cmd; } else { cmd->stackMapsOffsetX = 0; } CVMassert(CVMcmdStackMaps(cmd) == con.stackmaps); if (con.inliningInfo != NULL) { cmd->inliningInfoOffsetX = (CVMUint16 *)con.inliningInfo - (CVMUint16 *)cmd; } else { cmd->inliningInfoOffsetX = 0; } CVMassert(CVMcmdInliningInfo(cmd) == con.inliningInfo);#ifdef CVM_JIT_PATCHED_METHOD_INVOCATIONS if (con.callees != NULL) { CVMassert(CVMglobals.jit.pmiEnabled); cmd->calleesOffsetX = (CVMUint32*)con.callees - (CVMUint32 *)cmd; } else { cmd->calleesOffsetX = 0; } CVMassert(CVMcmdCallees(cmd) == con.callees);#endif#ifdef CVMJIT_PATCH_BASED_GC_CHECKS { if (con.gcCheckPcs != NULL) { cmd->gcCheckPCsOffsetX = (CVMUint16 *)con.gcCheckPcs - (CVMUint16 *)cmd; } else { cmd->gcCheckPCsOffsetX = 0; } CVMassert(CVMcmdGCCheckPCs(cmd) == con.gcCheckPcs); }#endif#ifdef CVMCPU_HAS_CP_REG { CVMUint8 *cp = CVMJITcbufLogicalToPhysical(&con, con.target.cpLogicalPC); cmd->cpBaseRegOffsetX = (CVMUint16 *)cp - (CVMUint16 *)cmd; CVMassert(CVMcmdCPBaseReg(cmd) == cp); }#endif CVMcmdMb(cmd) = mb; /* make sure we survive at least one gc */ CVMcmdEntryCount(cmd) = 0x2; /* * Make sure the cost is properly counted down. * A simplifying assumption in a couple of other spots. * Note how this is reset in the case of decompilation. */ CVMmbInvokeCostSet(mb, 0); /* * We must add the entry to the code cache and set startPC * atomically. The main thing we need to avoid is having * aging happening after the method is added to the code cache, * but before startPC is set. Since aging code will grab * the jitLock first, we are safe, since we own jitLock * for the duration of compilation */ CVMassert(CVMsysMutexIAmOwner(con.ee, &CVMglobals.jitLock)); { /* * The following will also make CVMmbIsCompiled() start * to return TRUE. We must do this last. */ CVMassert (!CVMmbIsCompiled(mb)); CVMmbStartPC(mb) = startPC; CVMmbJitInvoker(mb) = startPC; /* * We need to commit the code buffer while in the lock to * protect from races with decompilation. */ CVMJITcbufCommit(&con);#ifdef CVM_JIT_PATCHED_METHOD_INVOCATIONS /* If any compiled method calls this method, patch the call * to be a direct call to this compiled method. */ CVMJITPMIpatchCallsToMethod(mb, CVMJITPMI_PATCHSTATE_COMPILED);#endif } /* IAI-07: Notify JVMPI of compilation. */#ifdef CVM_JVMPI if (CVMjvmpiEventCompiledMethodLoadIsEnabled()) { CVMjvmpiPostCompiledMethodLoadEvent(ee, mb); }#endif /* IAI-07: Notify JVMTI of compilation. */#ifdef CVM_JVMTI if (CVMjvmtiShouldPostCompiledMethodLoad()) { CVMjvmtiPostCompiledMethodLoadEvent(ee, mb); }#endif CVMtraceJITStatus(("JS: COMPILED: size=%d startPC=0x%x %C.%M\n", CVMcmdCodeBufSize(cmd), startPC, CVMmbClassBlock(mb), mb));#ifdef CVM_JIT_PATCHED_METHOD_INVOCATIONS CVMtraceJITPatchedInvokesExec({ CVMJITPMIdumpMethodCalleeInfo(con.mb, CVM_FALSE); });#endif CVMJITstatsExec({ endTime = CVMtimeMillis(); CVMJITstatsRecordSetCount(&con, CVMJIT_STATS_COMPILATION_TIME, CVMlong2Int(CVMlongSub(endTime, startTime))); }); /* Update the per compilation cycle and global statistics: */#ifdef CVM_JIT_ESTIMATE_COMPILATION_SPEED if (CVMglobals.jit.doCSpeedMeasurement) { CVMglobals.jit.numberOfByteCodeBytesCompiled += con.codeLength; CVMglobals.jit.numberOfByteCodeBytesCompiledWithoutInlinedMethods += CVMjmdCodeLength(con.jmd); CVMglobals.jit.numberOfBytesOfGeneratedCode += CVMcmdCodeBufSize(cmd); }#endif CVMJITstatsUpdateStats(&con); CVMtraceJITStatsExec({CVMJITstatsDump(&con);}); } } else { if (con.codeBufAddr != NULL) { CVMassert(CVMsysMutexIAmOwner(con.ee, &CVMglobals.jitLock)); CVMJITcbufFree(con.codeBufAddr, CVM_FALSE); } if (con.resultCode == CVMJIT_CANNOT_COMPILE) { CVMglobals.jit.failedCompilationAttempts++; /* Mark method as bad */ badMethod(ee, mb); } } retVal = con.resultCode; done:#ifdef CVM_JIT_PATCHED_METHOD_INVOCATIONS /* We've probably already added some patchable method invokes to the database, so we need to remove them if compilation failed. */ if (retVal != CVMJIT_SUCCESS && needDestroyContext && con.callees != NULL){ /* * For each method directly called by this method, have that method * (the callee method) remove this method (the caller method) * from its entries in the patch table. */ CVMUint32 numCallees = (CVMUint32)con.callees[0]; CVMUint32 i; CVMassert(CVMglobals.jit.pmiEnabled); for (i = 1; i <= numCallees; i++) { CVMMethodBlock* calleeMb = con.callees[i]; /* Remove records. */ CVMJITPMIremovePatchRecords(con.mb, calleeMb, con.codeBufAddr, con.codeBufEnd); } }#endif switch (retVal) { case CVMJIT_SUCCESS: break; case CVMJIT_CANNOT_COMPILE: { /* Don't try again for as long as possible */ CVMmbInvokeCostSet(mb, CVMJIT_MAX_INVOKE_COST); CVMtraceJITError(("JE: CANNOT COMPILE %C.%M\n",
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?