DFGPlan.cpp 11.5 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"
55
#include "DFGSSALoweringPhase.h"
fpizlo@apple.com's avatar
fpizlo@apple.com committed
56
#include "DFGStackLayoutPhase.h"
57
#include "DFGStoreBarrierElisionPhase.h"
58
#include "DFGStrengthReductionPhase.h"
59
#include "DFGTierUpCheckInjectionPhase.h"
60 61 62 63
#include "DFGTypeCheckHoistingPhase.h"
#include "DFGUnificationPhase.h"
#include "DFGValidate.h"
#include "DFGVirtualRegisterAllocationPhase.h"
64
#include "DFGWatchpointCollectionPhase.h"
65
#include "OperandsInlines.h"
66 67 68 69
#include "Operations.h"
#include <wtf/CurrentTime.h>

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

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

Plan::~Plan()
{
}

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

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

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

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

    dfg.m_fixpointState = FixpointConverged;

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

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

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

        if (Options::llvmAlwaysFailsBeforeLink()) {
            FTL::fail(state);
            return FTLPath;
        }
        
310
        FTL::link(state);
311
        return FTLPath;
312
#else
313
        RELEASE_ASSERT_NOT_REACHED();
314
        return FailPath;
315
#endif // ENABLE(FTL_JIT)
316 317 318 319
    }
        
    default:
        RELEASE_ASSERT_NOT_REACHED();
320
        return FailPath;
321 322 323 324 325 326 327 328 329
    }
}

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

330
void Plan::reallyAdd(CommonData* commonData)
331
{
332
    watchpoints.reallyAdd(codeBlock.get(), *commonData);
333
    identifiers.reallyAdd(vm, commonData);
334 335 336
    weakReferences.reallyAdd(vm, commonData);
    transitions.reallyAdd(vm, commonData);
    writeBarriers.trigger(vm);
337 338
}

339 340 341 342 343 344 345
void Plan::notifyReady()
{
    callback->compilationDidBecomeReadyAsynchronously(codeBlock.get());
    isCompiled = true;
}

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

364 365 366 367 368
void Plan::finalizeAndNotifyCallback()
{
    callback->compilationDidComplete(codeBlock.get(), finalizeWithoutNotifyingCallback());
}

369
CompilationKey Plan::key()
370
{
371
    return CompilationKey(codeBlock->alternative(), mode);
372 373
}

374 375 376 377
} } // namespace JSC::DFG

#endif // ENABLE(DFG_JIT)