DFGPlan.cpp 9.58 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
/*
 * Copyright (C) 2013 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#include "config.h"
#include "DFGPlan.h"

#if ENABLE(DFG_JIT)

#include "DFGArgumentsSimplificationPhase.h"
#include "DFGBackwardsPropagationPhase.h"
#include "DFGByteCodeParser.h"
#include "DFGCFAPhase.h"
#include "DFGCFGSimplificationPhase.h"
#include "DFGCPSRethreadingPhase.h"
#include "DFGCSEPhase.h"
#include "DFGConstantFoldingPhase.h"
39
#include "DFGCriticalEdgeBreakingPhase.h"
40 41
#include "DFGDCEPhase.h"
#include "DFGFailedFinalizer.h"
42
#include "DFGFlushLivenessAnalysisPhase.h"
43 44
#include "DFGFixupPhase.h"
#include "DFGJITCompiler.h"
45
#include "DFGLICMPhase.h"
46
#include "DFGLivenessAnalysisPhase.h"
47
#include "DFGLoopPreHeaderCreationPhase.h"
48
#include "DFGOSRAvailabilityAnalysisPhase.h"
49 50
#include "DFGPredictionInjectionPhase.h"
#include "DFGPredictionPropagationPhase.h"
51
#include "DFGSSAConversionPhase.h"
52 53 54 55
#include "DFGTypeCheckHoistingPhase.h"
#include "DFGUnificationPhase.h"
#include "DFGValidate.h"
#include "DFGVirtualRegisterAllocationPhase.h"
56 57 58 59
#include "Operations.h"
#include <wtf/CurrentTime.h>

#if ENABLE(FTL_JIT)
60 61
#include "FTLCapabilities.h"
#include "FTLCompile.h"
62
#include "FTLFail.h"
63 64 65
#include "FTLLink.h"
#include "FTLLowerDFGToLLVM.h"
#include "FTLState.h"
66
#endif
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82

namespace JSC { namespace DFG {

static void dumpAndVerifyGraph(Graph& graph, const char* text)
{
    GraphDumpMode modeForFinalValidate = DumpGraph;
    if (verboseCompilationEnabled()) {
        dataLog(text, "\n");
        graph.dump();
        modeForFinalValidate = DontDumpGraph;
    }
    if (validationEnabled())
        validate(graph, modeForFinalValidate);
}

Plan::Plan(
83
    CompileMode compileMode, PassRefPtr<CodeBlock> passedCodeBlock, unsigned osrEntryBytecodeIndex,
84 85
    unsigned numVarsWithValues)
    : compileMode(compileMode)
86 87
    , vm(*passedCodeBlock->vm())
    , codeBlock(passedCodeBlock)
88 89 90
    , osrEntryBytecodeIndex(osrEntryBytecodeIndex)
    , numVarsWithValues(numVarsWithValues)
    , mustHandleValues(codeBlock->numParameters(), numVarsWithValues)
91 92
    , compilation(codeBlock->vm()->m_perBytecodeProfiler ? adoptRef(new Profiler::Compilation(codeBlock->vm()->m_perBytecodeProfiler->ensureBytecodesFor(codeBlock.get()), Profiler::DFG)) : 0)
    , identifiers(codeBlock.get())
93
    , weakReferences(codeBlock.get())
94
    , isCompiled(false)
95 96 97 98 99 100 101
{
}

Plan::~Plan()
{
}

102
void Plan::compileInThread(LongLivedState& longLivedState)
103
{
104 105 106 107
    double before = 0;
    if (Options::reportCompileTimes())
        before = currentTimeMS();
    
108 109 110
    SamplingRegion samplingRegion("DFG Compilation (Plan)");
    CompilationScope compilationScope;

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

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    CompilationPath path = compileInThreadImpl(longLivedState);

    RELEASE_ASSERT(finalizer);
    
    if (Options::reportCompileTimes()) {
        const char* pathName;
        switch (path) {
        case FailPath:
            pathName = "N/A (fail)";
            break;
        case DFGPath:
            pathName = "DFG";
            break;
        case FTLPath:
            pathName = "FTL";
            break;
ossy@webkit.org's avatar
ossy@webkit.org committed
130 131 132 133
        default:
            RELEASE_ASSERT_NOT_REACHED();
            pathName = "";
            break;
134
        }
135 136 137 138 139
        double now = currentTimeMS();
        dataLog("Optimized ", *codeBlock->alternative(), " with ", pathName, " in ", now - before, " ms");
        if (path == FTLPath)
            dataLog(" (DFG: ", beforeFTL - before, ", LLVM: ", now - beforeFTL, ")");
        dataLog(".\n");
140 141 142 143 144
    }
}

Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
{
145
    Graph dfg(vm, *this, longLivedState);
146 147 148
    
    if (!parse(dfg)) {
        finalizer = adoptPtr(new FailedFinalizer(*this));
149
        return FailPath;
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
    }
    
    // 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);
    
173
    unsigned count = 1;
174
    dfg.m_fixpointState = FixpointNotConverged;
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
    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);
197 198 199 200

    dfg.m_fixpointState = FixpointConverged;

    performStoreElimination(dfg);
201 202 203 204 205 206 207
    
    // 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);
    }
208 209 210 211 212 213

#if ENABLE(FTL_JIT)
    if (Options::useExperimentalFTL()
        && compileMode == CompileFunction
        && FTL::canCompile(dfg)) {
        
214
        performCriticalEdgeBreaking(dfg);
215
        performLoopPreHeaderCreation(dfg);
216 217 218 219
        performCPSRethreading(dfg);
        performSSAConversion(dfg);
        performLivenessAnalysis(dfg);
        performCFA(dfg);
220 221 222
        performLICM(dfg);
        performLivenessAnalysis(dfg);
        performCFA(dfg);
223 224 225 226 227
        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);
        
228 229 230 231 232 233 234
        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);
235 236 237 238
        
        if (Options::reportCompileTimes())
            beforeFTL = currentTimeMS();
        
239 240 241 242 243
        if (Options::llvmAlwaysFails()) {
            FTL::fail(state);
            return FTLPath;
        }
        
244 245
        FTL::compile(state);
        FTL::link(state);
246
        return FTLPath;
247
    }
248 249
#else
    RELEASE_ASSERT(!Options::useExperimentalFTL());
250 251
#endif // ENABLE(FTL_JIT)
    
252 253
    performCPSRethreading(dfg);
    performDCE(dfg);
254 255 256 257 258 259 260 261 262 263 264 265 266 267
    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();
    }
    
268
    return DFGPath;
269 270 271 272 273 274 275 276
}

bool Plan::isStillValid()
{
    return watchpoints.areStillValid()
        && chains.areStillValid();
}

277
void Plan::reallyAdd(CommonData* commonData)
278 279
{
    watchpoints.reallyAdd();
280
    identifiers.reallyAdd(vm, commonData);
281 282 283
    weakReferences.reallyAdd(vm, commonData);
    transitions.reallyAdd(vm, commonData);
    writeBarriers.trigger(vm);
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
}

CompilationResult Plan::finalize(RefPtr<JSC::JITCode>& jitCode, MacroAssemblerCodePtr* jitCodeWithArityCheck)
{
    if (!isStillValid())
        return CompilationInvalidated;
    
    bool result;
    if (compileMode == CompileFunction)
        result = finalizer->finalizeFunction(jitCode, *jitCodeWithArityCheck);
    else
        result = finalizer->finalize(jitCode);
    
    if (!result)
        return CompilationFailed;
    
300
    reallyAdd(jitCode->dfgCommon());
301 302 303 304
    
    return CompilationSuccessful;
}

305 306 307 308 309
CodeBlock* Plan::key()
{
    return codeBlock->alternative();
}

310 311 312 313
} } // namespace JSC::DFG

#endif // ENABLE(DFG_JIT)