2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "DFGArgumentsSimplificationPhase.h"
32 #include "DFGBackwardsPropagationPhase.h"
33 #include "DFGByteCodeParser.h"
34 #include "DFGCFAPhase.h"
35 #include "DFGCFGSimplificationPhase.h"
36 #include "DFGCPSRethreadingPhase.h"
37 #include "DFGCSEPhase.h"
38 #include "DFGConstantFoldingPhase.h"
39 #include "DFGCriticalEdgeBreakingPhase.h"
40 #include "DFGDCEPhase.h"
41 #include "DFGFailedFinalizer.h"
42 #include "DFGFixupPhase.h"
43 #include "DFGGraphSafepoint.h"
44 #include "DFGIntegerCheckCombiningPhase.h"
45 #include "DFGInvalidationPointInjectionPhase.h"
46 #include "DFGJITCompiler.h"
47 #include "DFGLICMPhase.h"
48 #include "DFGLivenessAnalysisPhase.h"
49 #include "DFGLoopPreHeaderCreationPhase.h"
50 #include "DFGOSRAvailabilityAnalysisPhase.h"
51 #include "DFGOSREntrypointCreationPhase.h"
52 #include "DFGPredictionInjectionPhase.h"
53 #include "DFGPredictionPropagationPhase.h"
54 #include "DFGResurrectionForValidationPhase.h"
55 #include "DFGSSAConversionPhase.h"
56 #include "DFGSSALoweringPhase.h"
57 #include "DFGStackLayoutPhase.h"
58 #include "DFGStaticExecutionCountEstimationPhase.h"
59 #include "DFGStoreBarrierElisionPhase.h"
60 #include "DFGStrengthReductionPhase.h"
61 #include "DFGTierUpCheckInjectionPhase.h"
62 #include "DFGTypeCheckHoistingPhase.h"
63 #include "DFGUnificationPhase.h"
64 #include "DFGValidate.h"
65 #include "DFGVirtualRegisterAllocationPhase.h"
66 #include "DFGWatchpointCollectionPhase.h"
68 #include "JSCInlines.h"
69 #include "OperandsInlines.h"
70 #include "ProfilerDatabase.h"
71 #include <wtf/CurrentTime.h>
74 #include "FTLCapabilities.h"
75 #include "FTLCompile.h"
78 #include "FTLLowerDFGToLLVM.h"
80 #include "InitializeLLVM.h"
83 namespace JSC
{ namespace DFG
{
85 static void dumpAndVerifyGraph(Graph
& graph
, const char* text
)
87 GraphDumpMode modeForFinalValidate
= DumpGraph
;
88 if (verboseCompilationEnabled(graph
.m_plan
.mode
)) {
91 modeForFinalValidate
= DontDumpGraph
;
93 if (validationEnabled())
94 validate(graph
, modeForFinalValidate
);
97 static Profiler::CompilationKind
profilerCompilationKindForMode(CompilationMode mode
)
100 case InvalidCompilationMode
:
101 RELEASE_ASSERT_NOT_REACHED();
102 return Profiler::DFG
;
104 return Profiler::DFG
;
106 return Profiler::FTL
;
107 case FTLForOSREntryMode
:
108 return Profiler::FTLForOSREntry
;
110 RELEASE_ASSERT_NOT_REACHED();
111 return Profiler::DFG
;
114 Plan::Plan(PassRefPtr
<CodeBlock
> passedCodeBlock
, CodeBlock
* profiledDFGCodeBlock
,
115 CompilationMode mode
, unsigned osrEntryBytecodeIndex
,
116 const Operands
<JSValue
>& mustHandleValues
)
117 : vm(*passedCodeBlock
->vm())
118 , codeBlock(passedCodeBlock
)
119 , profiledDFGCodeBlock(profiledDFGCodeBlock
)
121 , osrEntryBytecodeIndex(osrEntryBytecodeIndex
)
122 , mustHandleValues(mustHandleValues
)
123 , compilation(codeBlock
->vm()->m_perBytecodeProfiler
? adoptRef(new Profiler::Compilation(codeBlock
->vm()->m_perBytecodeProfiler
->ensureBytecodesFor(codeBlock
.get()), profilerCompilationKindForMode(mode
))) : 0)
124 , inlineCallFrames(adoptRef(new InlineCallFrameSet()))
125 , identifiers(codeBlock
.get())
126 , weakReferences(codeBlock
.get())
127 , willTryToTierUp(false)
136 bool Plan::reportCompileTimes() const
138 return Options::reportCompileTimes()
139 || (Options::reportFTLCompileTimes() && isFTL(mode
));
142 void Plan::compileInThread(LongLivedState
& longLivedState
, ThreadData
* threadData
)
144 this->threadData
= threadData
;
147 CString codeBlockName
;
148 if (reportCompileTimes()) {
149 before
= currentTimeMS();
150 codeBlockName
= toCString(*codeBlock
);
153 SamplingRegion
samplingRegion("DFG Compilation (Plan)");
154 CompilationScope compilationScope
;
156 if (logCompilationChanges(mode
))
157 dataLog("DFG(Plan) compiling ", *codeBlock
, " with ", mode
, ", number of instructions = ", codeBlock
->instructionCount(), "\n");
159 CompilationPath path
= compileInThreadImpl(longLivedState
);
161 RELEASE_ASSERT(path
== CancelPath
|| finalizer
);
162 RELEASE_ASSERT((path
== CancelPath
) == (stage
== Cancelled
));
164 if (reportCompileTimes()) {
165 const char* pathName
;
168 pathName
= "N/A (fail)";
177 pathName
= "Cancelled";
180 RELEASE_ASSERT_NOT_REACHED();
184 double now
= currentTimeMS();
185 dataLog("Optimized ", codeBlockName
, " using ", mode
, " with ", pathName
, " into ", finalizer
? finalizer
->codeSize() : 0, " bytes in ", now
- before
, " ms");
187 dataLog(" (DFG: ", beforeFTL
- before
, ", LLVM: ", now
- beforeFTL
, ")");
192 Plan::CompilationPath
Plan::compileInThreadImpl(LongLivedState
& longLivedState
)
194 if (verboseCompilationEnabled(mode
) && osrEntryBytecodeIndex
!= UINT_MAX
) {
196 dataLog("Compiler must handle OSR entry from bc#", osrEntryBytecodeIndex
, " with values: ", mustHandleValues
, "\n");
200 Graph
dfg(vm
, *this, longLivedState
);
203 finalizer
= adoptPtr(new FailedFinalizer(*this));
207 // By this point the DFG bytecode parser will have potentially mutated various tables
208 // in the CodeBlock. This is a good time to perform an early shrink, which is more
209 // powerful than a late one. It's safe to do so because we haven't generated any code
210 // that references any of the tables directly, yet.
211 codeBlock
->shrinkToFit(CodeBlock::EarlyShrink
);
213 if (validationEnabled())
216 performCPSRethreading(dfg
);
217 performUnification(dfg
);
218 performPredictionInjection(dfg
);
220 performStaticExecutionCountEstimation(dfg
);
222 if (mode
== FTLForOSREntryMode
) {
223 bool result
= performOSREntrypointCreation(dfg
);
225 finalizer
= adoptPtr(new FailedFinalizer(*this));
228 performCPSRethreading(dfg
);
231 if (validationEnabled())
234 performBackwardsPropagation(dfg
);
235 performPredictionPropagation(dfg
);
237 performInvalidationPointInjection(dfg
);
238 performTypeCheckHoisting(dfg
);
241 dfg
.m_fixpointState
= FixpointNotConverged
;
243 if (logCompilationChanges(mode
))
244 dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", count
);
245 bool changed
= false;
247 if (validationEnabled())
250 changed
|= performStrengthReduction(dfg
);
252 changed
|= performConstantFolding(dfg
);
253 changed
|= performArgumentsSimplification(dfg
);
254 changed
|= performCFGSimplification(dfg
);
255 changed
|= performCSE(dfg
);
260 performCPSRethreading(dfg
);
263 if (logCompilationChanges(mode
))
264 dataLogF("DFG optimization fixpoint converged in %u iterations.\n", count
);
266 dfg
.m_fixpointState
= FixpointConverged
;
268 // If we're doing validation, then run some analyses, to give them an opportunity
269 // to self-validate. Now is as good a time as any to do this.
270 if (validationEnabled()) {
271 dfg
.m_dominators
.computeIfNecessary(dfg
);
272 dfg
.m_naturalLoops
.computeIfNecessary(dfg
);
277 performTierUpCheckInjection(dfg
);
279 performStoreBarrierElision(dfg
);
280 performStoreElimination(dfg
);
281 performCPSRethreading(dfg
);
283 performStackLayout(dfg
);
284 performVirtualRegisterAllocation(dfg
);
285 performWatchpointCollection(dfg
);
286 dumpAndVerifyGraph(dfg
, "Graph after optimization:");
288 JITCompiler
dataFlowJIT(dfg
);
289 if (codeBlock
->codeType() == FunctionCode
) {
290 dataFlowJIT
.compileFunction();
291 dataFlowJIT
.linkFunction();
293 dataFlowJIT
.compile();
301 case FTLForOSREntryMode
: {
303 if (FTL::canCompile(dfg
) == FTL::CannotCompile
) {
304 finalizer
= adoptPtr(new FailedFinalizer(*this));
308 performCriticalEdgeBreaking(dfg
);
309 performLoopPreHeaderCreation(dfg
);
310 performCPSRethreading(dfg
);
311 performSSAConversion(dfg
);
312 performSSALowering(dfg
);
314 performLivenessAnalysis(dfg
);
317 performIntegerCheckCombining(dfg
);
320 // At this point we're not allowed to do any further code motion because our reasoning
321 // about code motion assumes that it's OK to insert GC points in random places.
323 performStoreBarrierElision(dfg
);
324 performLivenessAnalysis(dfg
);
326 if (Options::validateFTLOSRExitLiveness())
327 performResurrectionForValidation(dfg
);
328 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.
329 performStackLayout(dfg
);
330 performLivenessAnalysis(dfg
);
331 performOSRAvailabilityAnalysis(dfg
);
332 performWatchpointCollection(dfg
);
334 dumpAndVerifyGraph(dfg
, "Graph just before FTL lowering:");
337 Safepoint::Result safepointResult
;
339 GraphSafepoint
safepoint(dfg
, safepointResult
);
340 haveLLVM
= initializeLLVM();
342 if (safepointResult
.didGetCancelled())
346 finalizer
= adoptPtr(new FailedFinalizer(*this));
350 FTL::State
state(dfg
);
351 if (!FTL::lowerDFGToLLVM(state
)) {
356 if (reportCompileTimes())
357 beforeFTL
= currentTimeMS();
359 if (Options::llvmAlwaysFailsBeforeCompile()) {
364 FTL::compile(state
, safepointResult
);
365 if (safepointResult
.didGetCancelled())
368 if (Options::llvmAlwaysFailsBeforeLink()) {
373 if (state
.jitCode
->stackmaps
.stackSize() > Options::llvmMaxStackSize()) {
381 RELEASE_ASSERT_NOT_REACHED();
383 #endif // ENABLE(FTL_JIT)
387 RELEASE_ASSERT_NOT_REACHED();
392 bool Plan::isStillValid()
394 CodeBlock
* replacement
= codeBlock
->replacement();
397 // FIXME: This is almost certainly not necessary. There's no way for the baseline
398 // code to be replaced during a compilation, except if we delete the plan, in which
399 // case we wouldn't be here.
400 // https://bugs.webkit.org/show_bug.cgi?id=132707
401 if (codeBlock
->alternative() != replacement
->baselineVersion())
403 if (!watchpoints
.areStillValid())
405 if (!chains
.areStillValid())
410 void Plan::reallyAdd(CommonData
* commonData
)
412 watchpoints
.reallyAdd(codeBlock
.get(), *commonData
);
413 identifiers
.reallyAdd(vm
, commonData
);
414 weakReferences
.reallyAdd(vm
, commonData
);
415 transitions
.reallyAdd(vm
, commonData
);
416 writeBarriers
.trigger(vm
);
419 void Plan::notifyCompiling()
424 void Plan::notifyCompiled()
429 void Plan::notifyReady()
431 callback
->compilationDidBecomeReadyAsynchronously(codeBlock
.get());
435 CompilationResult
Plan::finalizeWithoutNotifyingCallback()
438 return CompilationInvalidated
;
441 if (codeBlock
->codeType() == FunctionCode
)
442 result
= finalizer
->finalizeFunction();
444 result
= finalizer
->finalize();
447 return CompilationFailed
;
449 reallyAdd(codeBlock
->jitCode()->dfgCommon());
451 return CompilationSuccessful
;
454 void Plan::finalizeAndNotifyCallback()
456 callback
->compilationDidComplete(codeBlock
.get(), finalizeWithoutNotifyingCallback());
459 CompilationKey
Plan::key()
461 return CompilationKey(codeBlock
->alternative(), mode
);
464 void Plan::checkLivenessAndVisitChildren(SlotVisitor
& visitor
, CodeBlockSet
& codeBlocks
)
466 if (!isKnownToBeLiveDuringGC())
469 for (unsigned i
= mustHandleValues
.size(); i
--;)
470 visitor
.appendUnbarrieredValue(&mustHandleValues
[i
]);
472 codeBlocks
.mark(codeBlock
->alternative());
473 codeBlocks
.mark(codeBlock
.get());
474 codeBlocks
.mark(profiledDFGCodeBlock
.get());
476 chains
.visitChildren(visitor
);
477 weakReferences
.visitChildren(visitor
);
478 writeBarriers
.visitChildren(visitor
);
479 transitions
.visitChildren(visitor
);
482 bool Plan::isKnownToBeLiveDuringGC()
484 if (stage
== Cancelled
)
486 if (!Heap::isMarked(codeBlock
->ownerExecutable()))
488 if (!codeBlock
->alternative()->isKnownToBeLiveDuringGC())
490 if (!!profiledDFGCodeBlock
&& !profiledDFGCodeBlock
->isKnownToBeLiveDuringGC())
498 profiledDFGCodeBlock
= nullptr;
499 mustHandleValues
.clear();
500 compilation
= nullptr;
502 inlineCallFrames
= nullptr;
503 watchpoints
= DesiredWatchpoints();
504 identifiers
= DesiredIdentifiers();
505 chains
= DesiredStructureChains();
506 weakReferences
= DesiredWeakReferences();
507 writeBarriers
= DesiredWriteBarriers();
508 transitions
= DesiredTransitions();
513 } } // namespace JSC::DFG
515 #endif // ENABLE(DFG_JIT)