void CallLinkStatus::computeDFGStatuses( CodeBlock* dfgCodeBlock, CallLinkStatus::ContextMap& map) { #if ENABLE(DFG_JIT) RELEASE_ASSERT(dfgCodeBlock->jitType() == JITCode::DFGJIT); CodeBlock* baselineCodeBlock = dfgCodeBlock->alternative(); for (auto iter = dfgCodeBlock->callLinkInfosBegin(); !!iter; ++iter) { CallLinkInfo& info = **iter; CodeOrigin codeOrigin = info.codeOrigin; bool takeSlowPath; bool badFunction; // Check if we had already previously made a terrible mistake in the FTL for this // code origin. Note that this is approximate because we could have a monovariant // inline in the FTL that ended up failing. We should fix that at some point by // having data structures to track the context of frequent exits. This is currently // challenging because it would require creating a CodeOrigin-based database in // baseline CodeBlocks, but those CodeBlocks don't really have a place to put the // InlineCallFrames. CodeBlock* currentBaseline = baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, baselineCodeBlock); { ConcurrentJITLocker locker(currentBaseline->m_lock); takeSlowPath = currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadCache, ExitFromFTL)) || currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadCacheWatchpoint, ExitFromFTL)) || currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadExecutable, ExitFromFTL)); badFunction = currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadFunction, ExitFromFTL)); } { ConcurrentJITLocker locker(dfgCodeBlock->m_lock); if (takeSlowPath) map.add(info.codeOrigin, takesSlowPath()); else { CallLinkStatus status = computeFor(locker, info); if (status.isSet()) { if (badFunction) status.makeClosureCall(); map.add(info.codeOrigin, status); } } } } #else UNUSED_PARAM(dfgCodeBlock); #endif // ENABLE(DFG_JIT) if (verbose) { dataLog("Context map:\n"); ContextMap::iterator iter = map.begin(); ContextMap::iterator end = map.end(); for (; iter != end; ++iter) { dataLog(" ", iter->key, ":\n"); dataLog(" ", iter->value, "\n"); } } }
CallLinkStatus CallLinkStatus::computeFor( CodeBlock* profiledBlock, unsigned bytecodeIndex, const CallLinkInfoMap& map) { ConcurrentJITLocker locker(profiledBlock->m_lock); UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); UNUSED_PARAM(map); #if ENABLE(DFG_JIT) if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache)) || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCacheWatchpoint)) || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadExecutable))) return takesSlowPath(); CallLinkInfo* callLinkInfo = map.get(CodeOrigin(bytecodeIndex)); if (!callLinkInfo) return computeFromLLInt(locker, profiledBlock, bytecodeIndex); CallLinkStatus result = computeFor(locker, *callLinkInfo); if (!result) return computeFromLLInt(locker, profiledBlock, bytecodeIndex); if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadFunction))) result.makeClosureCall(); return result; #else return CallLinkStatus(); #endif }
CallLinkStatus CallLinkStatus::computeFor( const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, CallLinkInfo& callLinkInfo, ExitSiteData exitSiteData) { CallLinkStatus result = computeFor(locker, profiledBlock, callLinkInfo); if (exitSiteData.m_badFunction) result.makeClosureCall(); if (exitSiteData.m_takesSlowPath) result.m_couldTakeSlowPath = true; return result; }
CallLinkStatus CallLinkStatus::computeFor( const ConcurrentJITLocker& locker, CallLinkInfo& callLinkInfo, ExitSiteData exitSiteData) { if (exitSiteData.m_takesSlowPath) return takesSlowPath(); CallLinkStatus result = computeFor(locker, callLinkInfo); if (exitSiteData.m_badFunction) result.makeClosureCall(); return result; }
CallLinkStatus CallLinkStatus::computeFor( const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, CallLinkInfo& callLinkInfo, ExitSiteData exitSiteData) { CallLinkStatus result = computeFor(locker, profiledBlock, callLinkInfo); if (exitSiteData.badFunction) { if (result.isBasedOnStub()) { // If we have a polymorphic stub, then having an exit site is not quite so useful. In // most cases, the information in the stub has higher fidelity. result.makeClosureCall(); } else { // We might not have a polymorphic stub for any number of reasons. When this happens, we // are in less certain territory, so exit sites mean a lot. result.m_couldTakeSlowPath = true; } } if (exitSiteData.takesSlowPath) result.m_couldTakeSlowPath = true; return result; }