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