GC constraint solving should be parallel
[WebKit-https.git] / Source / JavaScriptCore / ftl / FTLCompile.cpp
1 /*
2  * Copyright (C) 2015-2017 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 "FTLCompile.h"
28
29 #if ENABLE(FTL_JIT)
30
31 #include "AirCode.h"
32 #include "AirDisassembler.h"
33 #include "B3Generate.h"
34 #include "B3ProcedureInlines.h"
35 #include "B3StackSlot.h"
36 #include "B3Value.h"
37 #include "CodeBlockWithJITType.h"
38 #include "CCallHelpers.h"
39 #include "DFGCommon.h"
40 #include "DFGGraphSafepoint.h"
41 #include "DFGOperations.h"
42 #include "DataView.h"
43 #include "Disassembler.h"
44 #include "FTLJITCode.h"
45 #include "FTLThunks.h"
46 #include "JITSubGenerator.h"
47 #include "JSCInlines.h"
48 #include "LinkBuffer.h"
49 #include "PCToCodeOriginMap.h"
50 #include "ScratchRegisterAllocator.h"
51 #include <wtf/Function.h>
52
53 namespace JSC { namespace FTL {
54
55 using namespace DFG;
56
57 void compile(State& state, Safepoint::Result& safepointResult)
58 {
59     Graph& graph = state.graph;
60     CodeBlock* codeBlock = graph.m_codeBlock;
61     VM& vm = graph.m_vm;
62
63     if (shouldDumpDisassembly())
64         state.proc->code().setDisassembler(std::make_unique<B3::Air::Disassembler>());
65
66     {
67         GraphSafepoint safepoint(state.graph, safepointResult);
68
69         B3::prepareForGeneration(*state.proc);
70     }
71
72     if (safepointResult.didGetCancelled())
73         return;
74     RELEASE_ASSERT(!state.graph.m_vm.heap.worldIsStopped());
75     
76     if (state.allocationFailed)
77         return;
78     
79     std::unique_ptr<RegisterAtOffsetList> registerOffsets =
80         std::make_unique<RegisterAtOffsetList>(state.proc->calleeSaveRegisterAtOffsetList());
81     if (shouldDumpDisassembly())
82         dataLog("Unwind info for ", CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT), ": ", *registerOffsets, "\n");
83     state.graph.m_codeBlock->setCalleeSaveRegisters(WTFMove(registerOffsets));
84     ASSERT(!(state.proc->frameSize() % sizeof(EncodedJSValue)));
85     state.jitCode->common.frameRegisterCount = state.proc->frameSize() / sizeof(EncodedJSValue);
86
87     int localsOffset =
88         state.capturedValue->offsetFromFP() / sizeof(EncodedJSValue) + graph.m_nextMachineLocal;
89     if (shouldDumpDisassembly()) {
90         dataLog(
91             "localsOffset = ", localsOffset, " for stack slot: ",
92             pointerDump(state.capturedValue), " at ", RawPointer(state.capturedValue), "\n");
93     }
94     
95     for (unsigned i = graph.m_inlineVariableData.size(); i--;) {
96         InlineCallFrame* inlineCallFrame = graph.m_inlineVariableData[i].inlineCallFrame;
97         
98         if (inlineCallFrame->argumentCountRegister.isValid())
99             inlineCallFrame->argumentCountRegister += localsOffset;
100         
101         for (unsigned argument = inlineCallFrame->argumentsWithFixup.size(); argument-- > 1;) {
102             inlineCallFrame->argumentsWithFixup[argument] =
103                 inlineCallFrame->argumentsWithFixup[argument].withLocalsOffset(localsOffset);
104         }
105         
106         if (inlineCallFrame->isClosureCall) {
107             inlineCallFrame->calleeRecovery =
108                 inlineCallFrame->calleeRecovery.withLocalsOffset(localsOffset);
109         }
110
111     }
112
113     // Note that the scope register could be invalid here if the original code had CallEval but it
114     // got killed. That's because it takes the CallEval to cause the scope register to be kept alive
115     // unless the debugger is also enabled.
116     if (graph.needsScopeRegister() && codeBlock->scopeRegister().isValid())
117         codeBlock->setScopeRegister(codeBlock->scopeRegister() + localsOffset);
118
119     for (OSRExitDescriptor& descriptor : state.jitCode->osrExitDescriptors) {
120         for (unsigned i = descriptor.m_values.size(); i--;)
121             descriptor.m_values[i] = descriptor.m_values[i].withLocalsOffset(localsOffset);
122         for (ExitTimeObjectMaterialization* materialization : descriptor.m_materializations)
123             materialization->accountForLocalsOffset(localsOffset);
124     }
125
126     // We will add exception handlers while generating.
127     codeBlock->clearExceptionHandlers();
128
129     CCallHelpers jit(codeBlock);
130     B3::generate(*state.proc, jit);
131
132     // Emit the exception handler.
133     *state.exceptionHandler = jit.label();
134     jit.copyCalleeSavesToEntryFrameCalleeSavesBuffer(vm.topEntryFrame);
135     jit.move(MacroAssembler::TrustedImmPtr(&vm), GPRInfo::argumentGPR0);
136     jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
137     CCallHelpers::Call call = jit.call();
138     jit.jumpToExceptionHandler(vm);
139     jit.addLinkTask(
140         [=] (LinkBuffer& linkBuffer) {
141             linkBuffer.link(call, FunctionPtr(lookupExceptionHandler));
142         });
143
144     state.finalizer->b3CodeLinkBuffer = std::make_unique<LinkBuffer>(jit, codeBlock, JITCompilationCanFail);
145
146     if (state.finalizer->b3CodeLinkBuffer->didFailToAllocate()) {
147         state.allocationFailed = true;
148         return;
149     }
150     
151     B3::PCToOriginMap originMap = state.proc->releasePCToOriginMap();
152     if (vm.shouldBuilderPCToCodeOriginMapping())
153         codeBlock->setPCToCodeOriginMap(std::make_unique<PCToCodeOriginMap>(PCToCodeOriginMapBuilder(vm, WTFMove(originMap)), *state.finalizer->b3CodeLinkBuffer));
154
155     CodeLocationLabel label = state.finalizer->b3CodeLinkBuffer->locationOf(state.proc->entrypointLabel(0));
156     state.generatedFunction = label.executableAddress<GeneratedFunction>();
157     state.jitCode->initializeB3Byproducts(state.proc->releaseByproducts());
158
159     for (auto pair : state.graph.m_entrypointIndexToCatchBytecodeOffset) {
160         unsigned catchBytecodeOffset = pair.value;
161         unsigned entrypointIndex = pair.key;
162         Vector<FlushFormat> argumentFormats = state.graph.m_argumentFormats[entrypointIndex];
163         state.jitCode->common.appendCatchEntrypoint(
164             catchBytecodeOffset, state.finalizer->b3CodeLinkBuffer->locationOf(state.proc->entrypointLabel(entrypointIndex)).executableAddress(), WTFMove(argumentFormats));
165     }
166     state.jitCode->common.finalizeCatchEntrypoints();
167
168     if (B3::Air::Disassembler* disassembler = state.proc->code().disassembler()) {
169         PrintStream& out = WTF::dataFile();
170
171         out.print("Generated ", state.graph.m_plan.mode, " code for ", CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT), ", instruction count = ", state.graph.m_codeBlock->instructionCount(), ":\n");
172
173         LinkBuffer& linkBuffer = *state.finalizer->b3CodeLinkBuffer;
174         B3::Value* currentB3Value = nullptr;
175         Node* currentDFGNode = nullptr;
176
177         HashSet<B3::Value*> printedValues;
178         HashSet<Node*> printedNodes;
179         const char* dfgPrefix = "    ";
180         const char* b3Prefix  = "          ";
181         const char* airPrefix = "              ";
182         const char* asmPrefix = "                ";
183
184         auto printDFGNode = [&] (Node* node) {
185             if (currentDFGNode == node)
186                 return;
187
188             currentDFGNode = node;
189             if (!currentDFGNode)
190                 return;
191
192             HashSet<Node*> localPrintedNodes;
193             WTF::Function<void(Node*)> printNodeRecursive = [&] (Node* node) {
194                 if (printedNodes.contains(node) || localPrintedNodes.contains(node))
195                     return;
196
197                 localPrintedNodes.add(node);
198                 graph.doToChildren(node, [&] (Edge child) {
199                     printNodeRecursive(child.node());
200                 });
201                 graph.dump(out, dfgPrefix, node);
202             };
203             printNodeRecursive(node);
204             printedNodes.add(node);
205         };
206
207         auto printB3Value = [&] (B3::Value* value) {
208             if (currentB3Value == value)
209                 return;
210
211             currentB3Value = value;
212             if (!currentB3Value)
213                 return;
214
215             printDFGNode(bitwise_cast<Node*>(value->origin().data()));
216
217             HashSet<B3::Value*> localPrintedValues;
218             WTF::Function<void(B3::Value*)> printValueRecursive = [&] (B3::Value* value) {
219                 if (printedValues.contains(value) || localPrintedValues.contains(value))
220                     return;
221
222                 localPrintedValues.add(value);
223                 for (unsigned i = 0; i < value->numChildren(); i++)
224                     printValueRecursive(value->child(i));
225                 out.print(b3Prefix);
226                 value->deepDump(state.proc.get(), out);
227                 out.print("\n");
228             };
229
230             printValueRecursive(currentB3Value);
231             printedValues.add(value);
232         };
233
234         auto forEachInst = [&] (B3::Air::Inst& inst) {
235             printB3Value(inst.origin);
236         };
237
238         disassembler->dump(state.proc->code(), out, linkBuffer, airPrefix, asmPrefix, forEachInst);
239         linkBuffer.didAlreadyDisassemble();
240     }
241 }
242
243 } } // namespace JSC::FTL
244
245 #endif // ENABLE(FTL_JIT)
246