Replace WTF::move with WTFMove
[WebKit-https.git] / Source / JavaScriptCore / ftl / FTLLink.cpp
1 /*
2  * Copyright (C) 2013, 2014 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 "FTLLink.h"
28
29 #if ENABLE(FTL_JIT)
30
31 #include "CCallHelpers.h"
32 #include "CodeBlockWithJITType.h"
33 #include "DFGCommon.h"
34 #include "FTLJITCode.h"
35 #include "JITOperations.h"
36 #include "LLVMAPI.h"
37 #include "LinkBuffer.h"
38 #include "JSCInlines.h"
39 #include "ProfilerCompilation.h"
40 #include "VirtualRegister.h"
41
42 namespace JSC { namespace FTL {
43
44 using namespace DFG;
45
46 void link(State& state)
47 {
48     Graph& graph = state.graph;
49     CodeBlock* codeBlock = graph.m_codeBlock;
50     VM& vm = graph.m_vm;
51     
52     // LLVM will create its own jump tables as needed.
53     codeBlock->clearSwitchJumpTables();
54
55 #if !FTL_USES_B3
56     // What LLVM's stackmaps call stackSizeForLocals and what we call frameRegisterCount have a simple
57     // relationship, though it's not obvious from reading the code. The easiest way to understand them
58     // is to look at stackOffset, i.e. what you have to add to FP to get SP. For LLVM that is just:
59     //
60     //     stackOffset == -state.jitCode->stackmaps.stackSizeForLocals()
61     //
62     // The way we define frameRegisterCount is that it satisfies this equality:
63     //
64     //     stackOffset == virtualRegisterForLocal(frameRegisterCount - 1).offset() * sizeof(Register)
65     //
66     // We can simplify this when we apply virtualRegisterForLocal():
67     //
68     //     stackOffset == (-1 - (frameRegisterCount - 1)) * sizeof(Register)
69     //     stackOffset == (-1 - frameRegisterCount + 1) * sizeof(Register)
70     //     stackOffset == -frameRegisterCount * sizeof(Register)
71     //
72     // Therefore we just have:
73     //
74     //     frameRegisterCount == -stackOffset / sizeof(Register)
75     //
76     // If we substitute what we have above, we get:
77     //
78     //     frameRegisterCount == -(-state.jitCode->stackmaps.stackSizeForLocals()) / sizeof(Register)
79     //     frameRegisterCount == state.jitCode->stackmaps.stackSizeForLocals() / sizeof(Register)
80     state.jitCode->common.frameRegisterCount = state.jitCode->stackmaps.stackSizeForLocals() / sizeof(void*);
81 #endif
82     
83     state.jitCode->common.requiredRegisterCountForExit = graph.requiredRegisterCountForExit();
84     
85     if (!graph.m_plan.inlineCallFrames->isEmpty())
86         state.jitCode->common.inlineCallFrames = graph.m_plan.inlineCallFrames;
87     
88     graph.registerFrozenValues();
89
90     // Create the entrypoint. Note that we use this entrypoint totally differently
91     // depending on whether we're doing OSR entry or not.
92     CCallHelpers jit(&vm, codeBlock);
93     
94     std::unique_ptr<LinkBuffer> linkBuffer;
95
96     CCallHelpers::Address frame = CCallHelpers::Address(
97         CCallHelpers::stackPointerRegister, -static_cast<int32_t>(AssemblyHelpers::prologueStackPointerDelta()));
98     
99     if (Profiler::Compilation* compilation = graph.compilation()) {
100         compilation->addDescription(
101             Profiler::OriginStack(),
102             toCString("Generated FTL JIT code for ", CodeBlockWithJITType(codeBlock, JITCode::FTLJIT), ", instruction count = ", graph.m_codeBlock->instructionCount(), ":\n"));
103         
104         graph.ensureDominators();
105         graph.ensureNaturalLoops();
106         
107         const char* prefix = "    ";
108         
109         DumpContext dumpContext;
110         StringPrintStream out;
111         Node* lastNode = 0;
112         for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); ++blockIndex) {
113             BasicBlock* block = graph.block(blockIndex);
114             if (!block)
115                 continue;
116             
117             graph.dumpBlockHeader(out, prefix, block, Graph::DumpLivePhisOnly, &dumpContext);
118             compilation->addDescription(Profiler::OriginStack(), out.toCString());
119             out.reset();
120             
121             for (size_t nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
122                 Node* node = block->at(nodeIndex);
123                 
124                 Profiler::OriginStack stack;
125                 
126                 if (node->origin.semantic.isSet()) {
127                     stack = Profiler::OriginStack(
128                         *vm.m_perBytecodeProfiler, codeBlock, node->origin.semantic);
129                 }
130                 
131                 if (graph.dumpCodeOrigin(out, prefix, lastNode, node, &dumpContext)) {
132                     compilation->addDescription(stack, out.toCString());
133                     out.reset();
134                 }
135                 
136                 graph.dump(out, prefix, node, &dumpContext);
137                 compilation->addDescription(stack, out.toCString());
138                 out.reset();
139                 
140                 if (node->origin.semantic.isSet())
141                     lastNode = node;
142             }
143         }
144         
145         dumpContext.dump(out, prefix);
146         compilation->addDescription(Profiler::OriginStack(), out.toCString());
147         out.reset();
148
149         out.print("    Disassembly:\n");
150 #if FTL_USES_B3
151         out.print("        <not implemented yet>\n");
152 #else
153         for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) {
154             if (state.codeSectionNames[i] != SECTION_NAME("text"))
155                 continue;
156             
157             ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get();
158             disassemble(
159                 MacroAssemblerCodePtr(handle->start()), handle->sizeInBytes(),
160                 "      ", out, LLVMSubset);
161         }
162 #endif
163         compilation->addDescription(Profiler::OriginStack(), out.toCString());
164         out.reset();
165         
166         state.jitCode->common.compilation = compilation;
167     }
168     
169     switch (graph.m_plan.mode) {
170     case FTLMode: {
171         CCallHelpers::JumpList mainPathJumps;
172     
173         jit.load32(
174             frame.withOffset(sizeof(Register) * JSStack::ArgumentCount),
175             GPRInfo::regT1);
176         mainPathJumps.append(jit.branch32(
177             CCallHelpers::AboveOrEqual, GPRInfo::regT1,
178             CCallHelpers::TrustedImm32(codeBlock->numParameters())));
179         jit.emitFunctionPrologue();
180         jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
181         jit.store32(
182             CCallHelpers::TrustedImm32(CallSiteIndex(0).bits()),
183             CCallHelpers::tagFor(JSStack::ArgumentCount));
184         jit.storePtr(GPRInfo::callFrameRegister, &vm.topCallFrame);
185         CCallHelpers::Call callArityCheck = jit.call();
186 #if !ASSERT_DISABLED
187         // FIXME: need to make this call register with exception handling somehow. This is
188         // part of a bigger problem: FTL should be able to handle exceptions.
189         // https://bugs.webkit.org/show_bug.cgi?id=113622
190         // Until then, use a JIT ASSERT.
191         jit.load64(vm.addressOfException(), GPRInfo::regT1);
192         jit.jitAssertIsNull(GPRInfo::regT1);
193 #endif
194         jit.move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0);
195         jit.emitFunctionEpilogue();
196         mainPathJumps.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::argumentGPR0));
197         jit.emitFunctionPrologue();
198         CCallHelpers::Call callArityFixup = jit.call();
199         jit.emitFunctionEpilogue();
200         mainPathJumps.append(jit.jump());
201
202         linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail);
203         if (linkBuffer->didFailToAllocate()) {
204             state.allocationFailed = true;
205             return;
206         }
207         linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck);
208         linkBuffer->link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixupGenerator)).code().executableAddress()));
209         linkBuffer->link(mainPathJumps, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction)));
210
211         state.jitCode->initializeAddressForCall(MacroAssemblerCodePtr(bitwise_cast<void*>(state.generatedFunction)));
212         break;
213     }
214         
215     case FTLForOSREntryMode: {
216         // We jump to here straight from DFG code, after having boxed up all of the
217         // values into the scratch buffer. Everything should be good to go - at this
218         // point we've even done the stack check. Basically we just have to make the
219         // call to the LLVM-generated code.
220         CCallHelpers::Label start = jit.label();
221         jit.emitFunctionEpilogue();
222         CCallHelpers::Jump mainPathJump = jit.jump();
223         
224         linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail);
225         if (linkBuffer->didFailToAllocate()) {
226             state.allocationFailed = true;
227             return;
228         }
229         linkBuffer->link(mainPathJump, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction)));
230
231         state.jitCode->initializeAddressForCall(linkBuffer->locationOf(start));
232         break;
233     }
234         
235     default:
236         RELEASE_ASSERT_NOT_REACHED();
237         break;
238     }
239     
240     state.finalizer->entrypointLinkBuffer = WTFMove(linkBuffer);
241     state.finalizer->function = state.generatedFunction;
242     state.finalizer->jitCode = state.jitCode;
243 }
244
245 } } // namespace JSC::FTL
246
247 #endif // ENABLE(FTL_JIT)
248