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