Esempio n. 1
0
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");
        }
    }
}
Esempio n. 2
0
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
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}