예제 #1
0
static CompilationResult compileImpl(
    VM& vm, CodeBlock* codeBlock, CodeBlock* profiledDFGCodeBlock, CompilationMode mode,
    unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues,
    PassRefPtr<DeferredCompilationCallback> callback)
{
    SamplingRegion samplingRegion("DFG Compilation (Driver)");
    
    numCompilations++;
    
    ASSERT(codeBlock);
    ASSERT(codeBlock->alternative());
    ASSERT(codeBlock->alternative()->jitType() == JITCode::BaselineJIT);
    ASSERT(!profiledDFGCodeBlock || profiledDFGCodeBlock->jitType() == JITCode::DFGJIT);
    
    if (logCompilationChanges(mode))
        dataLog("DFG(Driver) compiling ", *codeBlock, " with ", mode, ", number of instructions = ", codeBlock->instructionCount(), "\n");
    
    // Make sure that any stubs that the DFG is going to use are initialized. We want to
    // make sure that all JIT code generation does finalization on the main thread.
    vm.getCTIStub(osrExitGenerationThunkGenerator);
    vm.getCTIStub(throwExceptionFromCallSlowPathGenerator);
    if (mode == DFGMode) {
        vm.getCTIStub(linkCallThunkGenerator);
        vm.getCTIStub(linkConstructThunkGenerator);
        vm.getCTIStub(linkClosureCallThunkGenerator);
        vm.getCTIStub(virtualCallThunkGenerator);
        vm.getCTIStub(virtualConstructThunkGenerator);
    } else {
        vm.getCTIStub(linkCallThatPreservesRegsThunkGenerator);
        vm.getCTIStub(linkConstructThatPreservesRegsThunkGenerator);
        vm.getCTIStub(linkClosureCallThatPreservesRegsThunkGenerator);
        vm.getCTIStub(virtualCallThatPreservesRegsThunkGenerator);
        vm.getCTIStub(virtualConstructThatPreservesRegsThunkGenerator);
    }
    
    if (CallEdgeLog::isEnabled())
        vm.ensureCallEdgeLog().processLog();

    if (vm.typeProfiler())
        vm.typeProfilerLog()->processLogEntries(ASCIILiteral("Preparing for DFG compilation."));
    
    RefPtr<Plan> plan = adoptRef(
        new Plan(codeBlock, profiledDFGCodeBlock, mode, osrEntryBytecodeIndex, mustHandleValues));
    
    if (Options::enableConcurrentJIT()) {
        Worklist* worklist = ensureGlobalWorklistFor(mode);
        plan->callback = callback;
        if (logCompilationChanges(mode))
            dataLog("Deferring DFG compilation of ", *codeBlock, " with queue length ", worklist->queueLength(), ".\n");
        worklist->enqueue(plan);
        return CompilationDeferred;
    }
    
    plan->compileInThread(*vm.dfgState, 0);
    return plan->finalizeWithoutNotifyingCallback();
}
예제 #2
0
파일: DFGPlan.cpp 프로젝트: PTaylour/webkit
void Plan::compileInThread(LongLivedState& longLivedState, ThreadData* threadData)
{
    this->threadData = threadData;
    
    double before = 0;
    if (reportCompileTimes())
        before = currentTimeMS();
    
    SamplingRegion samplingRegion("DFG Compilation (Plan)");
    CompilationScope compilationScope;

    if (logCompilationChanges(mode))
        dataLog("DFG(Plan) compiling ", *codeBlock, " with ", mode, ", number of instructions = ", codeBlock->instructionCount(), "\n");

    CompilationPath path = compileInThreadImpl(longLivedState);

    RELEASE_ASSERT(finalizer);
    
    if (reportCompileTimes()) {
        const char* pathName;
        switch (path) {
        case FailPath:
            pathName = "N/A (fail)";
            break;
        case DFGPath:
            pathName = "DFG";
            break;
        case FTLPath:
            pathName = "FTL";
            break;
        default:
            RELEASE_ASSERT_NOT_REACHED();
            pathName = "";
            break;
        }
        double now = currentTimeMS();
        dataLog("Optimized ", *codeBlock, " using ", mode, " with ", pathName, " into ", finalizer->codeSize(), " bytes in ", now - before, " ms");
        if (path == FTLPath)
            dataLog(" (DFG: ", beforeFTL - before, ", LLVM: ", now - beforeFTL, ")");
        dataLog(".\n");
    }
}
예제 #3
0
Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
{
    if (verboseCompilationEnabled() && osrEntryBytecodeIndex != UINT_MAX) {
        dataLog("\n");
        dataLog("Compiler must handle OSR entry from bc#", osrEntryBytecodeIndex, " with values: ", mustHandleValues, "\n");
        dataLog("\n");
    }
    
    Graph dfg(vm, *this, longLivedState);
    
    if (!parse(dfg)) {
        finalizer = adoptPtr(new FailedFinalizer(*this));
        return FailPath;
    }
    
    // By this point the DFG bytecode parser will have potentially mutated various tables
    // in the CodeBlock. This is a good time to perform an early shrink, which is more
    // powerful than a late one. It's safe to do so because we haven't generated any code
    // that references any of the tables directly, yet.
    codeBlock->shrinkToFit(CodeBlock::EarlyShrink);

    if (validationEnabled())
        validate(dfg);
    
    performCPSRethreading(dfg);
    performUnification(dfg);
    performPredictionInjection(dfg);
    
    if (mode == FTLForOSREntryMode) {
        bool result = performOSREntrypointCreation(dfg);
        if (!result) {
            finalizer = adoptPtr(new FailedFinalizer(*this));
            return FailPath;
        }
        performCPSRethreading(dfg);
    }
    
    if (validationEnabled())
        validate(dfg);
    
    performBackwardsPropagation(dfg);
    performPredictionPropagation(dfg);
    performFixup(dfg);
    performTypeCheckHoisting(dfg);
    
    unsigned count = 1;
    dfg.m_fixpointState = FixpointNotConverged;
    for (;; ++count) {
        if (logCompilationChanges())
            dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", count);
        bool changed = false;
        
        if (validationEnabled())
            validate(dfg);
        
        performCFA(dfg);
        changed |= performConstantFolding(dfg);
        changed |= performArgumentsSimplification(dfg);
        changed |= performCFGSimplification(dfg);
        changed |= performCSE(dfg);
        
        if (!changed)
            break;
        
        performCPSRethreading(dfg);
    }
    
    if (logCompilationChanges())
        dataLogF("DFG optimization fixpoint converged in %u iterations.\n", count);

    dfg.m_fixpointState = FixpointConverged;

    performStoreElimination(dfg);
    
    // If we're doing validation, then run some analyses, to give them an opportunity
    // to self-validate. Now is as good a time as any to do this.
    if (validationEnabled()) {
        dfg.m_dominators.computeIfNecessary(dfg);
        dfg.m_naturalLoops.computeIfNecessary(dfg);
    }

    switch (mode) {
    case DFGMode: {
        performTierUpCheckInjection(dfg);
        break;
    }
    
    case FTLMode:
    case FTLForOSREntryMode: {
#if ENABLE(FTL_JIT)
        if (FTL::canCompile(dfg) == FTL::CannotCompile) {
            finalizer = adoptPtr(new FailedFinalizer(*this));
            return FailPath;
        }
        
        performCriticalEdgeBreaking(dfg);
        performLoopPreHeaderCreation(dfg);
        performCPSRethreading(dfg);
        performSSAConversion(dfg);
        performLivenessAnalysis(dfg);
        performCFA(dfg);
        performLICM(dfg);
        performLivenessAnalysis(dfg);
        performCFA(dfg);
        performDCE(dfg); // We rely on this to convert dead SetLocals into the appropriate hint, and to kill dead code that won't be recognized as dead by LLVM.
        performStackLayout(dfg);
        performLivenessAnalysis(dfg);
        performFlushLivenessAnalysis(dfg);
        performOSRAvailabilityAnalysis(dfg);
        
        dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:");
        
        initializeLLVM();
        
        FTL::State state(dfg);
        FTL::lowerDFGToLLVM(state);
        
        if (Options::reportCompileTimes())
            beforeFTL = currentTimeMS();
        
        if (Options::llvmAlwaysFailsBeforeCompile()) {
            FTL::fail(state);
            return FTLPath;
        }
        
        FTL::compile(state);

        if (Options::llvmAlwaysFailsBeforeLink()) {
            FTL::fail(state);
            return FTLPath;
        }
        
        FTL::link(state);
        return FTLPath;
#else
        RELEASE_ASSERT_NOT_REACHED();
        break;
#endif // ENABLE(FTL_JIT)
    }
        
    default:
        RELEASE_ASSERT_NOT_REACHED();
        break;
    }
    
    performCPSRethreading(dfg);
    performDCE(dfg);
    performStackLayout(dfg);
    performVirtualRegisterAllocation(dfg);
    dumpAndVerifyGraph(dfg, "Graph after optimization:");

    JITCompiler dataFlowJIT(dfg);
    if (codeBlock->codeType() == FunctionCode) {
        dataFlowJIT.compileFunction();
        dataFlowJIT.linkFunction();
    } else {
        dataFlowJIT.compile();
        dataFlowJIT.link();
    }
    
    return DFGPath;
}
예제 #4
0
void Plan::compileInThread(LongLivedState& longLivedState, ThreadData* threadData)
{
    this->threadData = threadData;
    
    double before = 0;
    CString codeBlockName;
    if (UNLIKELY(computeCompileTimes()))
        before = monotonicallyIncreasingTimeMS();
    if (UNLIKELY(reportCompileTimes()))
        codeBlockName = toCString(*codeBlock);
    
    CompilationScope compilationScope;

    if (logCompilationChanges(mode) || Options::reportDFGPhaseTimes())
        dataLog("DFG(Plan) compiling ", *codeBlock, " with ", mode, ", number of instructions = ", codeBlock->instructionCount(), "\n");

    CompilationPath path = compileInThreadImpl(longLivedState);

    RELEASE_ASSERT(path == CancelPath || finalizer);
    RELEASE_ASSERT((path == CancelPath) == (stage == Cancelled));
    
    double after = 0;
    if (UNLIKELY(computeCompileTimes())) {
        after = monotonicallyIncreasingTimeMS();
    
        if (Options::reportTotalCompileTimes()) {
            if (isFTL(mode)) {
                totalFTLCompileTime += after - before;
                totalFTLDFGCompileTime += m_timeBeforeFTL - before;
                totalFTLB3CompileTime += after - m_timeBeforeFTL;
            } else
                totalDFGCompileTime += after - before;
        }
    }
    const char* pathName = nullptr;
    switch (path) {
    case FailPath:
        pathName = "N/A (fail)";
        break;
    case DFGPath:
        pathName = "DFG";
        break;
    case FTLPath:
        pathName = "FTL";
        break;
    case CancelPath:
        pathName = "Cancelled";
        break;
    default:
        RELEASE_ASSERT_NOT_REACHED();
        break;
    }
    if (codeBlock) { // codeBlock will be null if the compilation was cancelled.
        if (path == FTLPath)
            CODEBLOCK_LOG_EVENT(codeBlock, "ftlCompile", ("took ", after - before, " ms (DFG: ", m_timeBeforeFTL - before, ", B3: ", after - m_timeBeforeFTL, ") with ", pathName));
        else
            CODEBLOCK_LOG_EVENT(codeBlock, "dfgCompile", ("took ", after - before, " ms with ", pathName));
    }
    if (UNLIKELY(reportCompileTimes())) {
        dataLog("Optimized ", codeBlockName, " using ", mode, " with ", pathName, " into ", finalizer ? finalizer->codeSize() : 0, " bytes in ", after - before, " ms");
        if (path == FTLPath)
            dataLog(" (DFG: ", m_timeBeforeFTL - before, ", B3: ", after - m_timeBeforeFTL, ")");
        dataLog(".\n");
    }
}
inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck, unsigned osrEntryBytecodeIndex)
{
    SamplingRegion samplingRegion("DFG Compilation (Driver)");
    
    numCompilations++;
    
    ASSERT(codeBlock);
    ASSERT(codeBlock->alternative());
    ASSERT(codeBlock->alternative()->getJITType() == JITCode::BaselineJIT);

    ASSERT(osrEntryBytecodeIndex != UINT_MAX);

    if (!Options::useDFGJIT())
        return false;

    if (!Options::bytecodeRangeToDFGCompile().isInRange(codeBlock->instructionCount()))
        return false;
    
    if (logCompilationChanges())
        dataLog("DFG compiling ", *codeBlock, ", number of instructions = ", codeBlock->instructionCount(), "\n");
    
    // Derive our set of must-handle values. The compilation must be at least conservative
    // enough to allow for OSR entry with these values.
    unsigned numVarsWithValues;
    if (osrEntryBytecodeIndex)
        numVarsWithValues = codeBlock->m_numVars;
    else
        numVarsWithValues = 0;
    Operands<JSValue> mustHandleValues(codeBlock->numParameters(), numVarsWithValues);
    for (size_t i = 0; i < mustHandleValues.size(); ++i) {
        int operand = mustHandleValues.operandForIndex(i);
        if (operandIsArgument(operand)
            && !operandToArgument(operand)
            && compileMode == CompileFunction
            && codeBlock->specializationKind() == CodeForConstruct) {
            // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will
            // also never be used. It doesn't matter what we put into the value for this,
            // but it has to be an actual value that can be grokked by subsequent DFG passes,
            // so we sanitize it here by turning it into Undefined.
            mustHandleValues[i] = jsUndefined();
        } else
            mustHandleValues[i] = exec->uncheckedR(operand).jsValue();
    }
    
    Graph dfg(exec->vm(), codeBlock, osrEntryBytecodeIndex, mustHandleValues);
    if (!parse(exec, dfg))
        return false;
    
    // By this point the DFG bytecode parser will have potentially mutated various tables
    // in the CodeBlock. This is a good time to perform an early shrink, which is more
    // powerful than a late one. It's safe to do so because we haven't generated any code
    // that references any of the tables directly, yet.
    codeBlock->shrinkToFit(CodeBlock::EarlyShrink);

    if (validationEnabled())
    validate(dfg);
    
    performCPSRethreading(dfg);
    performUnification(dfg);
    performPredictionInjection(dfg);
    
    if (validationEnabled())
        validate(dfg);
    
    performBackwardsPropagation(dfg);
    performPredictionPropagation(dfg);
    performFixup(dfg);
    performTypeCheckHoisting(dfg);
    
    dfg.m_fixpointState = FixpointNotConverged;

    performCSE(dfg);
    performArgumentsSimplification(dfg);
    performCPSRethreading(dfg); // This should usually be a no-op since CSE rarely dethreads, and arguments simplification rarely does anything.
        performCFA(dfg);
    performConstantFolding(dfg);
    performCFGSimplification(dfg);

    dfg.m_fixpointState = FixpointConverged;

    performStoreElimination(dfg);
    performCPSRethreading(dfg);
    performDCE(dfg);
    performVirtualRegisterAllocation(dfg);

    GraphDumpMode modeForFinalValidate = DumpGraph;
    if (verboseCompilationEnabled()) {
        dataLogF("Graph after optimization:\n");
    dfg.dump();
    modeForFinalValidate = DontDumpGraph;
    }
    if (validationEnabled())
    validate(dfg, modeForFinalValidate);
    
    JITCompiler dataFlowJIT(dfg);
    bool result;
    if (compileMode == CompileFunction) {
        ASSERT(jitCodeWithArityCheck);
        
        result = dataFlowJIT.compileFunction(jitCode, *jitCodeWithArityCheck);
    } else {
        ASSERT(compileMode == CompileOther);
        ASSERT(!jitCodeWithArityCheck);
        
        result = dataFlowJIT.compile(jitCode);
    }
    
    return result;
}
예제 #6
0
static CompilationResult compileImpl(
    ExecState* exec, CodeBlock* codeBlock, CompilationMode mode,
    unsigned osrEntryBytecodeIndex, PassRefPtr<DeferredCompilationCallback> callback,
    Worklist* worklist)
{
    SamplingRegion samplingRegion("DFG Compilation (Driver)");
    
    numCompilations++;
    
    ASSERT(codeBlock);
    ASSERT(codeBlock->alternative());
    ASSERT(codeBlock->alternative()->jitType() == JITCode::BaselineJIT);
    
    ASSERT(osrEntryBytecodeIndex != UINT_MAX);

    if (!Options::useDFGJIT() || !MacroAssembler::supportsFloatingPoint())
        return CompilationFailed;

    if (!Options::bytecodeRangeToDFGCompile().isInRange(codeBlock->instructionCount()))
        return CompilationFailed;
    
    if (logCompilationChanges())
        dataLog("DFG(Driver) compiling ", *codeBlock, ", number of instructions = ", codeBlock->instructionCount(), "\n");
    
    VM& vm = exec->vm();
    
    // Make sure that any stubs that the DFG is going to use are initialized. We want to
    // make sure that al JIT code generation does finalization on the main thread.
    vm.getCTIStub(osrExitGenerationThunkGenerator);
    vm.getCTIStub(throwExceptionFromCallSlowPathGenerator);
    vm.getCTIStub(linkCallThunkGenerator);
    vm.getCTIStub(linkConstructThunkGenerator);
    vm.getCTIStub(linkClosureCallThunkGenerator);
    vm.getCTIStub(virtualCallThunkGenerator);
    vm.getCTIStub(virtualConstructThunkGenerator);
#if ENABLE(FTL_JIT)
    vm.getCTIStub(FTL::osrExitGenerationThunkGenerator);
#endif
    
    // Derive our set of must-handle values. The compilation must be at least conservative
    // enough to allow for OSR entry with these values.
    unsigned numVarsWithValues;
    if (osrEntryBytecodeIndex)
        numVarsWithValues = codeBlock->m_numVars;
    else
        numVarsWithValues = 0;
    RefPtr<Plan> plan = adoptRef(
        new Plan(codeBlock, mode, osrEntryBytecodeIndex, numVarsWithValues));
    for (size_t i = 0; i < plan->mustHandleValues.size(); ++i) {
        int operand = plan->mustHandleValues.operandForIndex(i);
        if (operandIsArgument(operand)
            && !operandToArgument(operand)
            && codeBlock->codeType() == FunctionCode
            && codeBlock->specializationKind() == CodeForConstruct) {
            // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will
            // also never be used. It doesn't matter what we put into the value for this,
            // but it has to be an actual value that can be grokked by subsequent DFG passes,
            // so we sanitize it here by turning it into Undefined.
            plan->mustHandleValues[i] = jsUndefined();
        } else
            plan->mustHandleValues[i] = exec->uncheckedR(operand).jsValue();
    }
    
    if (worklist) {
        plan->callback = callback;
        if (logCompilationChanges())
            dataLog("Deferring DFG compilation of ", *codeBlock, " with queue length ", worklist->queueLength(), ".\n");
        worklist->enqueue(plan);
        return CompilationDeferred;
    }
    
    plan->compileInThread(*vm.dfgState);
    return plan->finalizeWithoutNotifyingCallback();
}
예제 #7
0
파일: DFGPlan.cpp 프로젝트: cos2004/webkit
void Plan::compileInThread(LongLivedState& longLivedState, ThreadData* threadData)
{
    this->threadData = threadData;
    
    double before = 0;
    CString codeBlockName;
    if (computeCompileTimes())
        before = monotonicallyIncreasingTimeMS();
    if (reportCompileTimes())
        codeBlockName = toCString(*codeBlock);
    
    SamplingRegion samplingRegion("DFG Compilation (Plan)");
    CompilationScope compilationScope;

    if (logCompilationChanges(mode))
        dataLog("DFG(Plan) compiling ", *codeBlock, " with ", mode, ", number of instructions = ", codeBlock->instructionCount(), "\n");

    CompilationPath path = compileInThreadImpl(longLivedState);

    RELEASE_ASSERT(path == CancelPath || finalizer);
    RELEASE_ASSERT((path == CancelPath) == (stage == Cancelled));
    
    double after = 0;
    if (computeCompileTimes())
        after = monotonicallyIncreasingTimeMS();
    
    if (Options::reportTotalCompileTimes()) {
        if (isFTL(mode)) {
            totalFTLCompileTime += after - before;
            totalFTLDFGCompileTime += m_timeBeforeFTL - before;
            totalFTLB3CompileTime += after - m_timeBeforeFTL;
        } else
            totalDFGCompileTime += after - before;
    }
    
    if (reportCompileTimes()) {
        const char* pathName;
        switch (path) {
        case FailPath:
            pathName = "N/A (fail)";
            break;
        case DFGPath:
            pathName = "DFG";
            break;
        case FTLPath:
            pathName = "FTL";
            break;
        case CancelPath:
            pathName = "Cancelled";
            break;
        default:
            RELEASE_ASSERT_NOT_REACHED();
#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
            pathName = "";
#endif
            break;
        }
        dataLog("Optimized ", codeBlockName, " using ", mode, " with ", pathName, " into ", finalizer ? finalizer->codeSize() : 0, " bytes in ", after - before, " ms");
        if (path == FTLPath)
            dataLog(" (DFG: ", m_timeBeforeFTL - before, ", B3: ", after - m_timeBeforeFTL, ")");
        dataLog(".\n");
    }
}
예제 #8
0
Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
{
    Graph dfg(vm, *this, longLivedState);
    
    if (!parse(dfg)) {
        finalizer = adoptPtr(new FailedFinalizer(*this));
        return FailPath;
    }
    
    // By this point the DFG bytecode parser will have potentially mutated various tables
    // in the CodeBlock. This is a good time to perform an early shrink, which is more
    // powerful than a late one. It's safe to do so because we haven't generated any code
    // that references any of the tables directly, yet.
    codeBlock->shrinkToFit(CodeBlock::EarlyShrink);

    if (validationEnabled())
        validate(dfg);
    
    performCPSRethreading(dfg);
    performUnification(dfg);
    performPredictionInjection(dfg);
    
    if (validationEnabled())
        validate(dfg);
    
    performBackwardsPropagation(dfg);
    performPredictionPropagation(dfg);
    performFixup(dfg);
    performTypeCheckHoisting(dfg);
    
    unsigned count = 1;
    dfg.m_fixpointState = FixpointNotConverged;
    for (;; ++count) {
        if (logCompilationChanges())
            dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", count);
        bool changed = false;
        
        if (validationEnabled())
            validate(dfg);
        
        performCFA(dfg);
        changed |= performConstantFolding(dfg);
        changed |= performArgumentsSimplification(dfg);
        changed |= performCFGSimplification(dfg);
        changed |= performCSE(dfg);
        
        if (!changed)
            break;
        
        performCPSRethreading(dfg);
    }
    
    if (logCompilationChanges())
        dataLogF("DFG optimization fixpoint converged in %u iterations.\n", count);

    dfg.m_fixpointState = FixpointConverged;

    performStoreElimination(dfg);
    
    // If we're doing validation, then run some analyses, to give them an opportunity
    // to self-validate. Now is as good a time as any to do this.
    if (validationEnabled()) {
        dfg.m_dominators.computeIfNecessary(dfg);
        dfg.m_naturalLoops.computeIfNecessary(dfg);
    }

#if ENABLE(FTL_JIT)
    if (Options::useExperimentalFTL()
        && compileMode == CompileFunction
        && FTL::canCompile(dfg)) {
        
        performCriticalEdgeBreaking(dfg);
        performLoopPreHeaderCreation(dfg);
        performCPSRethreading(dfg);
        performSSAConversion(dfg);
        performLivenessAnalysis(dfg);
        performCFA(dfg);
        performLICM(dfg);
        performLivenessAnalysis(dfg);
        performCFA(dfg);
        performDCE(dfg); // We rely on this to convert dead SetLocals into the appropriate hint, and to kill dead code that won't be recognized as dead by LLVM.
        performLivenessAnalysis(dfg);
        performFlushLivenessAnalysis(dfg);
        performOSRAvailabilityAnalysis(dfg);
        
        dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:");
        
        // FIXME: Support OSR entry.
        // https://bugs.webkit.org/show_bug.cgi?id=113625
        
        FTL::State state(dfg);
        FTL::lowerDFGToLLVM(state);
        
        if (Options::reportCompileTimes())
            beforeFTL = currentTimeMS();
        
        if (Options::llvmAlwaysFails()) {
            FTL::fail(state);
            return FTLPath;
        }
        
        FTL::compile(state);
        FTL::link(state);
        return FTLPath;
    }
#endif // ENABLE(FTL_JIT)
    
    performCPSRethreading(dfg);
    performDCE(dfg);
    performVirtualRegisterAllocation(dfg);
    dumpAndVerifyGraph(dfg, "Graph after optimization:");

    JITCompiler dataFlowJIT(dfg);
    if (compileMode == CompileFunction) {
        dataFlowJIT.compileFunction();
        dataFlowJIT.linkFunction();
    } else {
        ASSERT(compileMode == CompileOther);
        
        dataFlowJIT.compile();
        dataFlowJIT.link();
    }
    
    return DFGPath;
}