The DFG should be able to tier-up and OSR enter into the FTL
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGPlan.cpp
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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. 
24  */
25
26 #include "config.h"
27 #include "DFGPlan.h"
28
29 #if ENABLE(DFG_JIT)
30
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 "DFGFlushLivenessAnalysisPhase.h"
43 #include "DFGFixupPhase.h"
44 #include "DFGJITCompiler.h"
45 #include "DFGLICMPhase.h"
46 #include "DFGLivenessAnalysisPhase.h"
47 #include "DFGLoopPreHeaderCreationPhase.h"
48 #include "DFGOSRAvailabilityAnalysisPhase.h"
49 #include "DFGOSREntrypointCreationPhase.h"
50 #include "DFGPredictionInjectionPhase.h"
51 #include "DFGPredictionPropagationPhase.h"
52 #include "DFGSSAConversionPhase.h"
53 #include "DFGTierUpCheckInjectionPhase.h"
54 #include "DFGTypeCheckHoistingPhase.h"
55 #include "DFGUnificationPhase.h"
56 #include "DFGValidate.h"
57 #include "DFGVirtualRegisterAllocationPhase.h"
58 #include "OperandsInlines.h"
59 #include "Operations.h"
60 #include <wtf/CurrentTime.h>
61
62 #if ENABLE(FTL_JIT)
63 #include "FTLCapabilities.h"
64 #include "FTLCompile.h"
65 #include "FTLFail.h"
66 #include "FTLLink.h"
67 #include "FTLLowerDFGToLLVM.h"
68 #include "FTLState.h"
69 #endif
70
71 namespace JSC { namespace DFG {
72
73 static void dumpAndVerifyGraph(Graph& graph, const char* text)
74 {
75     GraphDumpMode modeForFinalValidate = DumpGraph;
76     if (verboseCompilationEnabled()) {
77         dataLog(text, "\n");
78         graph.dump();
79         modeForFinalValidate = DontDumpGraph;
80     }
81     if (validationEnabled())
82         validate(graph, modeForFinalValidate);
83 }
84
85 Plan::Plan(
86     PassRefPtr<CodeBlock> passedCodeBlock, CompilationMode mode,
87     unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
88     : vm(*passedCodeBlock->vm())
89     , codeBlock(passedCodeBlock)
90     , mode(mode)
91     , osrEntryBytecodeIndex(osrEntryBytecodeIndex)
92     , mustHandleValues(mustHandleValues)
93     , compilation(codeBlock->vm()->m_perBytecodeProfiler ? adoptRef(new Profiler::Compilation(codeBlock->vm()->m_perBytecodeProfiler->ensureBytecodesFor(codeBlock.get()), Profiler::DFG)) : 0)
94     , identifiers(codeBlock.get())
95     , weakReferences(codeBlock.get())
96     , isCompiled(false)
97 {
98 }
99
100 Plan::~Plan()
101 {
102 }
103
104 void Plan::compileInThread(LongLivedState& longLivedState)
105 {
106     double before = 0;
107     if (Options::reportCompileTimes())
108         before = currentTimeMS();
109     
110     SamplingRegion samplingRegion("DFG Compilation (Plan)");
111     CompilationScope compilationScope;
112
113     if (logCompilationChanges())
114         dataLog("DFG(Plan) compiling ", *codeBlock, " with ", mode, ", number of instructions = ", codeBlock->instructionCount(), "\n");
115
116     CompilationPath path = compileInThreadImpl(longLivedState);
117
118     RELEASE_ASSERT(finalizer);
119     
120     if (Options::reportCompileTimes()) {
121         const char* pathName;
122         switch (path) {
123         case FailPath:
124             pathName = "N/A (fail)";
125             break;
126         case DFGPath:
127             pathName = "DFG";
128             break;
129         case FTLPath:
130             pathName = "FTL";
131             break;
132         default:
133             RELEASE_ASSERT_NOT_REACHED();
134             pathName = "";
135             break;
136         }
137         double now = currentTimeMS();
138         dataLog("Optimized ", *codeBlock->alternative(), " using ", mode, " with ", pathName, " in ", now - before, " ms");
139         if (path == FTLPath)
140             dataLog(" (DFG: ", beforeFTL - before, ", LLVM: ", now - beforeFTL, ")");
141         dataLog(".\n");
142     }
143 }
144
145 Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
146 {
147     if (verboseCompilationEnabled() && osrEntryBytecodeIndex != UINT_MAX) {
148         dataLog("\n");
149         dataLog("Compiler must handle OSR entry from bc#", osrEntryBytecodeIndex, " with values: ", mustHandleValues, "\n");
150         dataLog("\n");
151     }
152     
153     Graph dfg(vm, *this, longLivedState);
154     
155     if (!parse(dfg)) {
156         finalizer = adoptPtr(new FailedFinalizer(*this));
157         return FailPath;
158     }
159     
160     // By this point the DFG bytecode parser will have potentially mutated various tables
161     // in the CodeBlock. This is a good time to perform an early shrink, which is more
162     // powerful than a late one. It's safe to do so because we haven't generated any code
163     // that references any of the tables directly, yet.
164     codeBlock->shrinkToFit(CodeBlock::EarlyShrink);
165
166     if (validationEnabled())
167         validate(dfg);
168     
169     performCPSRethreading(dfg);
170     performUnification(dfg);
171     performPredictionInjection(dfg);
172     
173     if (mode == FTLForOSREntryMode) {
174         bool result = performOSREntrypointCreation(dfg);
175         if (!result) {
176             finalizer = adoptPtr(new FailedFinalizer(*this));
177             return FailPath;
178         }
179         performCPSRethreading(dfg);
180     }
181     
182     if (validationEnabled())
183         validate(dfg);
184     
185     performBackwardsPropagation(dfg);
186     performPredictionPropagation(dfg);
187     performFixup(dfg);
188     performTypeCheckHoisting(dfg);
189     
190     unsigned count = 1;
191     dfg.m_fixpointState = FixpointNotConverged;
192     for (;; ++count) {
193         if (logCompilationChanges())
194             dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", count);
195         bool changed = false;
196         
197         if (validationEnabled())
198             validate(dfg);
199         
200         performCFA(dfg);
201         changed |= performConstantFolding(dfg);
202         changed |= performArgumentsSimplification(dfg);
203         changed |= performCFGSimplification(dfg);
204         changed |= performCSE(dfg);
205         
206         if (!changed)
207             break;
208         
209         performCPSRethreading(dfg);
210     }
211     
212     if (logCompilationChanges())
213         dataLogF("DFG optimization fixpoint converged in %u iterations.\n", count);
214
215     dfg.m_fixpointState = FixpointConverged;
216
217     performStoreElimination(dfg);
218     
219     // If we're doing validation, then run some analyses, to give them an opportunity
220     // to self-validate. Now is as good a time as any to do this.
221     if (validationEnabled()) {
222         dfg.m_dominators.computeIfNecessary(dfg);
223         dfg.m_naturalLoops.computeIfNecessary(dfg);
224     }
225
226     switch (mode) {
227     case DFGMode: {
228         performTierUpCheckInjection(dfg);
229         break;
230     }
231     
232     case FTLMode:
233     case FTLForOSREntryMode: {
234 #if ENABLE(FTL_JIT)
235         if (FTL::canCompile(dfg) == FTL::CannotCompile) {
236             finalizer = adoptPtr(new FailedFinalizer(*this));
237             return FailPath;
238         }
239         
240         performCriticalEdgeBreaking(dfg);
241         performLoopPreHeaderCreation(dfg);
242         performCPSRethreading(dfg);
243         performSSAConversion(dfg);
244         performLivenessAnalysis(dfg);
245         performCFA(dfg);
246         performLICM(dfg);
247         performLivenessAnalysis(dfg);
248         performCFA(dfg);
249         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.
250         performLivenessAnalysis(dfg);
251         performFlushLivenessAnalysis(dfg);
252         performOSRAvailabilityAnalysis(dfg);
253         
254         dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:");
255         
256         // FIXME: Support OSR entry.
257         // https://bugs.webkit.org/show_bug.cgi?id=113625
258         
259         FTL::State state(dfg);
260         FTL::lowerDFGToLLVM(state);
261         
262         if (Options::reportCompileTimes())
263             beforeFTL = currentTimeMS();
264         
265         if (Options::llvmAlwaysFails()) {
266             FTL::fail(state);
267             return FTLPath;
268         }
269         
270         FTL::compile(state);
271         FTL::link(state);
272         return FTLPath;
273 #else
274         RELEASE_ASSERT_NOT_REACHED();
275         break;
276 #endif // ENABLE(FTL_JIT)
277     }
278         
279     default:
280         RELEASE_ASSERT_NOT_REACHED();
281         break;
282     }
283     
284     performCPSRethreading(dfg);
285     performDCE(dfg);
286     performVirtualRegisterAllocation(dfg);
287     dumpAndVerifyGraph(dfg, "Graph after optimization:");
288
289     JITCompiler dataFlowJIT(dfg);
290     if (codeBlock->codeType() == FunctionCode) {
291         dataFlowJIT.compileFunction();
292         dataFlowJIT.linkFunction();
293     } else {
294         dataFlowJIT.compile();
295         dataFlowJIT.link();
296     }
297     
298     return DFGPath;
299 }
300
301 bool Plan::isStillValid()
302 {
303     return watchpoints.areStillValid()
304         && chains.areStillValid();
305 }
306
307 void Plan::reallyAdd(CommonData* commonData)
308 {
309     watchpoints.reallyAdd();
310     identifiers.reallyAdd(vm, commonData);
311     weakReferences.reallyAdd(vm, commonData);
312     transitions.reallyAdd(vm, commonData);
313     writeBarriers.trigger(vm);
314 }
315
316 void Plan::notifyReady()
317 {
318     callback->compilationDidBecomeReadyAsynchronously(codeBlock.get());
319     isCompiled = true;
320 }
321
322 CompilationResult Plan::finalizeWithoutNotifyingCallback()
323 {
324     if (!isStillValid())
325         return CompilationInvalidated;
326     
327     bool result;
328     if (codeBlock->codeType() == FunctionCode)
329         result = finalizer->finalizeFunction();
330     else
331         result = finalizer->finalize();
332     
333     if (!result)
334         return CompilationFailed;
335     
336     reallyAdd(codeBlock->jitCode()->dfgCommon());
337     
338     return CompilationSuccessful;
339 }
340
341 void Plan::finalizeAndNotifyCallback()
342 {
343     callback->compilationDidComplete(codeBlock.get(), finalizeWithoutNotifyingCallback());
344 }
345
346 CompilationKey Plan::key()
347 {
348     return CompilationKey(codeBlock->alternative(), mode);
349 }
350
351 } } // namespace JSC::DFG
352
353 #endif // ENABLE(DFG_JIT)
354