AssemblyHelpers should not have a VM field
[WebKit.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.collectorBelievesThatTheWorldIsStopped());
75     
76     if (state.allocationFailed)
77         return;
78     
79     std::unique_ptr<RegisterAtOffsetList> registerOffsets =
80         std::make_unique<RegisterAtOffsetList>(state.proc->calleeSaveRegisters());
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->arguments.size(); argument-- > 1;) {
102             inlineCallFrame->arguments[argument] =
103                 inlineCallFrame->arguments[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.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(vm);
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>(
145         vm, jit, codeBlock, JITCompilationCanFail);
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     state.generatedFunction = bitwise_cast<GeneratedFunction>(
156         state.finalizer->b3CodeLinkBuffer->entrypoint().executableAddress());
157     state.jitCode->initializeB3Byproducts(state.proc->releaseByproducts());
158
159     if (B3::Air::Disassembler* disassembler = state.proc->code().disassembler()) {
160         PrintStream& out = WTF::dataFile();
161
162         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");
163
164         LinkBuffer& linkBuffer = *state.finalizer->b3CodeLinkBuffer;
165         B3::Value* currentB3Value = nullptr;
166         Node* currentDFGNode = nullptr;
167
168         HashSet<B3::Value*> printedValues;
169         HashSet<Node*> printedNodes;
170         const char* dfgPrefix = "    ";
171         const char* b3Prefix  = "          ";
172         const char* airPrefix = "              ";
173         const char* asmPrefix = "                ";
174
175         auto printDFGNode = [&] (Node* node) {
176             if (currentDFGNode == node)
177                 return;
178
179             currentDFGNode = node;
180             if (!currentDFGNode)
181                 return;
182
183             HashSet<Node*> localPrintedNodes;
184             WTF::Function<void(Node*)> printNodeRecursive = [&] (Node* node) {
185                 if (printedNodes.contains(node) || localPrintedNodes.contains(node))
186                     return;
187
188                 localPrintedNodes.add(node);
189                 graph.doToChildren(node, [&] (Edge child) {
190                     printNodeRecursive(child.node());
191                 });
192                 graph.dump(out, dfgPrefix, node);
193             };
194             printNodeRecursive(node);
195             printedNodes.add(node);
196         };
197
198         auto printB3Value = [&] (B3::Value* value) {
199             if (currentB3Value == value)
200                 return;
201
202             currentB3Value = value;
203             if (!currentB3Value)
204                 return;
205
206             printDFGNode(bitwise_cast<Node*>(value->origin().data()));
207
208             HashSet<B3::Value*> localPrintedValues;
209             WTF::Function<void(B3::Value*)> printValueRecursive = [&] (B3::Value* value) {
210                 if (printedValues.contains(value) || localPrintedValues.contains(value))
211                     return;
212
213                 localPrintedValues.add(value);
214                 for (unsigned i = 0; i < value->numChildren(); i++)
215                     printValueRecursive(value->child(i));
216                 out.print(b3Prefix);
217                 value->deepDump(state.proc.get(), out);
218                 out.print("\n");
219             };
220
221             printValueRecursive(currentB3Value);
222             printedValues.add(value);
223         };
224
225         auto forEachInst = [&] (B3::Air::Inst& inst) {
226             printB3Value(inst.origin);
227         };
228
229         disassembler->dump(state.proc->code(), out, linkBuffer, airPrefix, asmPrefix, forEachInst);
230         linkBuffer.didAlreadyDisassemble();
231     }
232 }
233
234 } } // namespace JSC::FTL
235
236 #endif // ENABLE(FTL_JIT)
237