DFGPlan.cpp 11.3 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
#include "DFGFixupPhase.h"
44
#include "DFGInvalidationPointInjectionPhase.h"
45
#include "DFGJITCompiler.h"
46
#include "DFGLICMPhase.h"
47
#include "DFGLivenessAnalysisPhase.h"
48
#include "DFGLoopPreHeaderCreationPhase.h"
49
#include "DFGOSRAvailabilityAnalysisPhase.h"
50
#include "DFGOSREntrypointCreationPhase.h"
51 52
#include "DFGPredictionInjectionPhase.h"
#include "DFGPredictionPropagationPhase.h"
53
#include "DFGResurrectionForValidationPhase.h"
54
#include "DFGSSAConversionPhase.h"
fpizlo@apple.com's avatar
fpizlo@apple.com committed
55
#include "DFGStackLayoutPhase.h"
56
#include "DFGStrengthReductionPhase.h"
57
#include "DFGTierUpCheckInjectionPhase.h"
58 59 60 61
#include "DFGTypeCheckHoistingPhase.h"
#include "DFGUnificationPhase.h"
#include "DFGValidate.h"
#include "DFGVirtualRegisterAllocationPhase.h"
62
#include "DFGWatchpointCollectionPhase.h"
63
#include "OperandsInlines.h"
64 65 66 67
#include "Operations.h"
#include <wtf/CurrentTime.h>

#if ENABLE(FTL_JIT)
68 69
#include "FTLCapabilities.h"
#include "FTLCompile.h"
70
#include "FTLFail.h"
71 72 73
#include "FTLLink.h"
#include "FTLLowerDFGToLLVM.h"
#include "FTLState.h"
74
#include "InitializeLLVM.h"
75
#endif
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

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(
92
    PassRefPtr<CodeBlock> passedCodeBlock, CompilationMode mode,
93
    unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
94
    : vm(*passedCodeBlock->vm())
95
    , codeBlock(passedCodeBlock)
96
    , mode(mode)
97
    , osrEntryBytecodeIndex(osrEntryBytecodeIndex)
98
    , mustHandleValues(mustHandleValues)
99 100
    , compilation(codeBlock->vm()->m_perBytecodeProfiler ? adoptRef(new Profiler::Compilation(codeBlock->vm()->m_perBytecodeProfiler->ensureBytecodesFor(codeBlock.get()), Profiler::DFG)) : 0)
    , identifiers(codeBlock.get())
101
    , weakReferences(codeBlock.get())
102
    , isCompiled(false)
103 104 105 106 107 108 109
{
}

Plan::~Plan()
{
}

110
void Plan::compileInThread(LongLivedState& longLivedState)
111
{
112 113 114 115
    double before = 0;
    if (Options::reportCompileTimes())
        before = currentTimeMS();
    
116 117 118
    SamplingRegion samplingRegion("DFG Compilation (Plan)");
    CompilationScope compilationScope;

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

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    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
138 139 140 141
        default:
            RELEASE_ASSERT_NOT_REACHED();
            pathName = "";
            break;
142
        }
143
        double now = currentTimeMS();
144
        dataLog("Optimized ", *codeBlock->alternative(), " using ", mode, " with ", pathName, " in ", now - before, " ms");
145 146 147
        if (path == FTLPath)
            dataLog(" (DFG: ", beforeFTL - before, ", LLVM: ", now - beforeFTL, ")");
        dataLog(".\n");
148 149 150 151 152
    }
}

Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
{
153 154 155 156 157 158
    if (verboseCompilationEnabled() && osrEntryBytecodeIndex != UINT_MAX) {
        dataLog("\n");
        dataLog("Compiler must handle OSR entry from bc#", osrEntryBytecodeIndex, " with values: ", mustHandleValues, "\n");
        dataLog("\n");
    }
    
159
    Graph dfg(vm, *this, longLivedState);
160 161 162
    
    if (!parse(dfg)) {
        finalizer = adoptPtr(new FailedFinalizer(*this));
163
        return FailPath;
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    }
    
    // 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);
    
179 180 181 182 183 184 185 186 187
    if (mode == FTLForOSREntryMode) {
        bool result = performOSREntrypointCreation(dfg);
        if (!result) {
            finalizer = adoptPtr(new FailedFinalizer(*this));
            return FailPath;
        }
        performCPSRethreading(dfg);
    }
    
188 189 190 191 192 193
    if (validationEnabled())
        validate(dfg);
    
    performBackwardsPropagation(dfg);
    performPredictionPropagation(dfg);
    performFixup(dfg);
194
    performInvalidationPointInjection(dfg);
195 196
    performTypeCheckHoisting(dfg);
    
197
    unsigned count = 1;
198
    dfg.m_fixpointState = FixpointNotConverged;
199 200 201 202 203 204 205 206
    for (;; ++count) {
        if (logCompilationChanges())
            dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", count);
        bool changed = false;
        
        if (validationEnabled())
            validate(dfg);
        
207
        changed |= performStrengthReduction(dfg);
208 209 210 211 212 213 214 215 216 217 218 219 220 221
        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);
222 223 224 225

    dfg.m_fixpointState = FixpointConverged;

    performStoreElimination(dfg);
226 227 228 229 230 231 232
    
    // 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);
    }
233

234 235 236
    switch (mode) {
    case DFGMode: {
        performTierUpCheckInjection(dfg);
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

        performCPSRethreading(dfg);
        performDCE(dfg);
        performStackLayout(dfg);
        performVirtualRegisterAllocation(dfg);
        performWatchpointCollection(dfg);
        dumpAndVerifyGraph(dfg, "Graph after optimization:");
        
        JITCompiler dataFlowJIT(dfg);
        if (codeBlock->codeType() == FunctionCode) {
            dataFlowJIT.compileFunction();
            dataFlowJIT.linkFunction();
        } else {
            dataFlowJIT.compile();
            dataFlowJIT.link();
        }
        
        return DFGPath;
255 256 257 258
    }
    
    case FTLMode:
    case FTLForOSREntryMode: {
259
#if ENABLE(FTL_JIT)
260 261 262 263
        if (FTL::canCompile(dfg) == FTL::CannotCompile) {
            finalizer = adoptPtr(new FailedFinalizer(*this));
            return FailPath;
        }
264
        
265
        performCriticalEdgeBreaking(dfg);
266
        performLoopPreHeaderCreation(dfg);
267 268 269 270
        performCPSRethreading(dfg);
        performSSAConversion(dfg);
        performLivenessAnalysis(dfg);
        performCFA(dfg);
271 272 273
        performLICM(dfg);
        performLivenessAnalysis(dfg);
        performCFA(dfg);
274 275
        if (Options::validateFTLOSRExitLiveness())
            performResurrectionForValidation(dfg);
276
        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.
fpizlo@apple.com's avatar
fpizlo@apple.com committed
277
        performStackLayout(dfg);
278 279 280
        performLivenessAnalysis(dfg);
        performFlushLivenessAnalysis(dfg);
        performOSRAvailabilityAnalysis(dfg);
281
        performWatchpointCollection(dfg);
282
        
283 284
        dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:");
        
285
        initializeLLVM();
286 287 288
        
        FTL::State state(dfg);
        FTL::lowerDFGToLLVM(state);
289 290 291 292
        
        if (Options::reportCompileTimes())
            beforeFTL = currentTimeMS();
        
293
        if (Options::llvmAlwaysFailsBeforeCompile()) {
294 295 296 297
            FTL::fail(state);
            return FTLPath;
        }
        
298
        FTL::compile(state);
299 300 301 302 303 304

        if (Options::llvmAlwaysFailsBeforeLink()) {
            FTL::fail(state);
            return FTLPath;
        }
        
305
        FTL::link(state);
306
        return FTLPath;
307
#else
308
        RELEASE_ASSERT_NOT_REACHED();
309
        return FailPath;
310
#endif // ENABLE(FTL_JIT)
311 312 313 314
    }
        
    default:
        RELEASE_ASSERT_NOT_REACHED();
315
        return FailPath;
316 317 318 319 320 321 322 323 324
    }
}

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

325
void Plan::reallyAdd(CommonData* commonData)
326
{
327
    watchpoints.reallyAdd(codeBlock.get(), *commonData);
328
    identifiers.reallyAdd(vm, commonData);
329 330 331
    weakReferences.reallyAdd(vm, commonData);
    transitions.reallyAdd(vm, commonData);
    writeBarriers.trigger(vm);
332 333
}

334 335 336 337 338 339 340
void Plan::notifyReady()
{
    callback->compilationDidBecomeReadyAsynchronously(codeBlock.get());
    isCompiled = true;
}

CompilationResult Plan::finalizeWithoutNotifyingCallback()
341 342 343 344 345
{
    if (!isStillValid())
        return CompilationInvalidated;
    
    bool result;
346 347
    if (codeBlock->codeType() == FunctionCode)
        result = finalizer->finalizeFunction();
348
    else
349
        result = finalizer->finalize();
350 351 352 353
    
    if (!result)
        return CompilationFailed;
    
354
    reallyAdd(codeBlock->jitCode()->dfgCommon());
355 356 357 358
    
    return CompilationSuccessful;
}

359 360 361 362 363
void Plan::finalizeAndNotifyCallback()
{
    callback->compilationDidComplete(codeBlock.get(), finalizeWithoutNotifyingCallback());
}

364
CompilationKey Plan::key()
365
{
366
    return CompilationKey(codeBlock->alternative(), mode);
367 368
}

369 370 371 372
} } // namespace JSC::DFG

#endif // ENABLE(DFG_JIT)