The DFG should be able to tier-up and OSR enter into the FTL
[WebKit-https.git] / Source / JavaScriptCore / ftl / FTLLink.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 "FTLLink.h"
28
29 #if ENABLE(FTL_JIT)
30
31 #include "CallFrameInlines.h"
32 #include "CodeBlockWithJITType.h"
33 #include "DFGCCallHelpers.h"
34 #include "DFGCommon.h"
35 #include "FTLJITCode.h"
36 #include "JITStubs.h"
37 #include "LinkBuffer.h"
38 #include <wtf/LLVMHeaders.h>
39
40 namespace JSC { namespace FTL {
41
42 using namespace DFG;
43
44 static void compileEntry(CCallHelpers& jit)
45 {
46     jit.preserveReturnAddressAfterCall(GPRInfo::regT2);
47     jit.emitPutToCallFrameHeader(GPRInfo::regT2, JSStack::ReturnPC);
48     jit.emitPutImmediateToCallFrameHeader(jit.codeBlock(), JSStack::CodeBlock);
49 }
50
51 void link(State& state)
52 {
53     CodeBlock* codeBlock = state.graph.m_codeBlock;
54     
55     // LLVM will create its own jump tables as needed.
56     codeBlock->clearSwitchJumpTables();
57     
58     // Create the entrypoint. Note that we use this entrypoint totally differently
59     // depending on whether we're doing OSR entry or not.
60     // FIXME: Except for OSR entry, this is a total kludge - LLVM should just use our
61     // calling convention.
62     // https://bugs.webkit.org/show_bug.cgi?id=113621
63     CCallHelpers jit(&state.graph.m_vm, codeBlock);
64     
65     OwnPtr<LinkBuffer> linkBuffer;
66     CCallHelpers::Label arityCheck;
67     switch (state.graph.m_plan.mode) {
68     case FTLMode: {
69         compileEntry(jit);
70     
71         // This part is only necessary for functions. We currently only compile functions.
72         
73         CCallHelpers::Label fromArityCheck = jit.label();
74         
75         // Plant a check that sufficient space is available in the JSStack.
76         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291
77         jit.addPtr(
78             CCallHelpers::TrustedImm32(codeBlock->m_numCalleeRegisters * sizeof(Register)),
79             GPRInfo::callFrameRegister, GPRInfo::regT1);
80         CCallHelpers::Jump stackCheck = jit.branchPtr(
81             CCallHelpers::Below,
82             CCallHelpers::AbsoluteAddress(state.graph.m_vm.interpreter->stack().addressOfEnd()),
83             GPRInfo::regT1);
84         CCallHelpers::Label fromStackCheck = jit.label();
85         
86         jit.setupArgumentsExecState();
87         jit.move(
88             CCallHelpers::TrustedImmPtr(reinterpret_cast<void*>(state.generatedFunction)),
89             GPRInfo::nonArgGPR0);
90         jit.call(GPRInfo::nonArgGPR0);
91         jit.emitGetFromCallFrameHeaderPtr(JSStack::ReturnPC, GPRInfo::regT1);
92         jit.emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, GPRInfo::callFrameRegister);
93         jit.restoreReturnAddressBeforeReturn(GPRInfo::regT1);
94         jit.ret();
95         
96         stackCheck.link(&jit);
97         jit.move(CCallHelpers::stackPointerRegister, GPRInfo::argumentGPR0);
98         jit.poke(
99             GPRInfo::callFrameRegister,
100             OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
101         
102         jit.store32(
103             CCallHelpers::TrustedImm32(CallFrame::Location::encodeAsBytecodeOffset(0)),
104             CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)));
105         CCallHelpers::Call callStackCheck = jit.call();
106         // FIXME: need to make this call register with exception handling somehow. This is
107         // part of a bigger problem: FTL should be able to handle exceptions.
108         // https://bugs.webkit.org/show_bug.cgi?id=113622
109         jit.jump(fromStackCheck);
110         
111         arityCheck = jit.label();
112         compileEntry(jit);
113         jit.load32(
114             CCallHelpers::payloadFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)),
115             GPRInfo::regT1);
116         jit.branch32(
117             CCallHelpers::AboveOrEqual, GPRInfo::regT1,
118             CCallHelpers::TrustedImm32(codeBlock->numParameters()))
119             .linkTo(fromArityCheck, &jit);
120         jit.move(CCallHelpers::stackPointerRegister, GPRInfo::argumentGPR0);
121         jit.poke(
122             GPRInfo::callFrameRegister,
123             OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
124         jit.store32(
125             CCallHelpers::TrustedImm32(CallFrame::Location::encodeAsBytecodeOffset(0)),
126             CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)));
127         CCallHelpers::Call callArityCheck = jit.call();
128         // FIXME: need to make this call register with exception handling somehow. This is
129         // part of a bigger problem: FTL should be able to handle exceptions.
130         // https://bugs.webkit.org/show_bug.cgi?id=113622
131         jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT0).linkTo(fromArityCheck, &jit);
132         CCallHelpers::Call callArityFixup = jit.call();
133         jit.jump(fromArityCheck);
134         
135         linkBuffer = adoptPtr(new LinkBuffer(state.graph.m_vm, &jit, codeBlock, JITCompilationMustSucceed));
136         linkBuffer->link(callStackCheck, cti_stack_check);
137         linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);
138         linkBuffer->link(callArityFixup, FunctionPtr((state.graph.m_vm.getCTIStub(arityFixup)).code().executableAddress()));
139         break;
140     }
141         
142     case FTLForOSREntryMode: {
143         // We jump to here straight from DFG code, after having boxed up all of the
144         // values into the scratch buffer. Everything should be good to go - at this
145         // point we've even done the stack check. Basically we just have to make the
146         // call to the LLVM-generated code.
147         jit.setupArgumentsExecState();
148         jit.move(
149             CCallHelpers::TrustedImmPtr(reinterpret_cast<void*>(state.generatedFunction)),
150             GPRInfo::nonArgGPR0);
151         jit.call(GPRInfo::nonArgGPR0);
152         jit.emitGetFromCallFrameHeaderPtr(JSStack::ReturnPC, GPRInfo::regT1);
153         jit.emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, GPRInfo::callFrameRegister);
154         jit.restoreReturnAddressBeforeReturn(GPRInfo::regT1);
155         jit.ret();
156         
157         linkBuffer = adoptPtr(new LinkBuffer(
158             state.graph.m_vm, &jit, codeBlock, JITCompilationMustSucceed));
159         break;
160     }
161         
162     default:
163         RELEASE_ASSERT_NOT_REACHED();
164         break;
165     }
166     
167     state.finalizer->initializeEntrypointLinkBuffer(linkBuffer.release());
168     state.finalizer->initializeFunction(state.generatedFunction);
169     state.finalizer->initializeArityCheck(arityCheck);
170     state.finalizer->initializeJITCode(state.jitCode);
171 }
172
173 } } // namespace JSC::FTL
174
175 #endif // ENABLE(FTL_JIT)
176