2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
31 #include "ArityCheckFailReturnThunks.h"
32 #include "CCallHelpers.h"
33 #include "CodeBlockWithJITType.h"
34 #include "DFGCommon.h"
35 #include "FTLJITCode.h"
36 #include "JITOperations.h"
39 #include "LinkBuffer.h"
40 #include "JSCInlines.h"
41 #include "ProfilerCompilation.h"
42 #include "VirtualRegister.h"
44 namespace JSC
{ namespace FTL
{
48 void link(State
& state
)
50 Graph
& graph
= state
.graph
;
51 CodeBlock
* codeBlock
= graph
.m_codeBlock
;
54 // LLVM will create its own jump tables as needed.
55 codeBlock
->clearSwitchJumpTables();
57 // FIXME: Need to know the real frame register count.
58 // https://bugs.webkit.org/show_bug.cgi?id=125727
59 state
.jitCode
->common
.frameRegisterCount
= 1000;
61 state
.jitCode
->common
.requiredRegisterCountForExit
= graph
.requiredRegisterCountForExit();
63 if (!graph
.m_plan
.inlineCallFrames
->isEmpty())
64 state
.jitCode
->common
.inlineCallFrames
= graph
.m_plan
.inlineCallFrames
;
66 // Create the entrypoint. Note that we use this entrypoint totally differently
67 // depending on whether we're doing OSR entry or not.
68 CCallHelpers
jit(&vm
, codeBlock
);
70 OwnPtr
<LinkBuffer
> linkBuffer
;
72 CCallHelpers::Address frame
= CCallHelpers::Address(
73 CCallHelpers::stackPointerRegister
, -static_cast<int32_t>(AssemblyHelpers::prologueStackPointerDelta()));
75 if (Profiler::Compilation
* compilation
= graph
.compilation()) {
76 compilation
->addDescription(
77 Profiler::OriginStack(),
78 toCString("Generated FTL JIT code for ", CodeBlockWithJITType(codeBlock
, JITCode::FTLJIT
), ", instruction count = ", graph
.m_codeBlock
->instructionCount(), ":\n"));
80 graph
.m_dominators
.computeIfNecessary(graph
);
81 graph
.m_naturalLoops
.computeIfNecessary(graph
);
83 const char* prefix
= " ";
85 DumpContext dumpContext
;
86 StringPrintStream out
;
88 for (size_t blockIndex
= 0; blockIndex
< graph
.numBlocks(); ++blockIndex
) {
89 BasicBlock
* block
= graph
.block(blockIndex
);
93 graph
.dumpBlockHeader(out
, prefix
, block
, Graph::DumpLivePhisOnly
, &dumpContext
);
94 compilation
->addDescription(Profiler::OriginStack(), out
.toCString());
97 for (size_t nodeIndex
= 0; nodeIndex
< block
->size(); ++nodeIndex
) {
98 Node
* node
= block
->at(nodeIndex
);
99 if (!node
->willHaveCodeGenOrOSR() && !Options::showAllDFGNodes())
102 Profiler::OriginStack stack
;
104 if (node
->origin
.semantic
.isSet()) {
105 stack
= Profiler::OriginStack(
106 *vm
.m_perBytecodeProfiler
, codeBlock
, node
->origin
.semantic
);
109 if (graph
.dumpCodeOrigin(out
, prefix
, lastNode
, node
, &dumpContext
)) {
110 compilation
->addDescription(stack
, out
.toCString());
114 graph
.dump(out
, prefix
, node
, &dumpContext
);
115 compilation
->addDescription(stack
, out
.toCString());
118 if (node
->origin
.semantic
.isSet())
123 dumpContext
.dump(out
, prefix
);
124 compilation
->addDescription(Profiler::OriginStack(), out
.toCString());
127 out
.print(" Disassembly:\n");
128 for (unsigned i
= 0; i
< state
.jitCode
->handles().size(); ++i
) {
129 if (state
.codeSectionNames
[i
] != "__text")
132 ExecutableMemoryHandle
* handle
= state
.jitCode
->handles()[i
].get();
134 MacroAssemblerCodePtr(handle
->start()), handle
->sizeInBytes(),
135 " ", out
, LLVMSubset
);
137 compilation
->addDescription(Profiler::OriginStack(), out
.toCString());
140 state
.jitCode
->common
.compilation
= compilation
;
143 switch (graph
.m_plan
.mode
) {
145 CCallHelpers::JumpList mainPathJumps
;
148 frame
.withOffset(sizeof(Register
) * JSStack::ArgumentCount
),
150 mainPathJumps
.append(jit
.branch32(
151 CCallHelpers::AboveOrEqual
, GPRInfo::regT1
,
152 CCallHelpers::TrustedImm32(codeBlock
->numParameters())));
153 jit
.emitFunctionPrologue();
154 jit
.move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
156 CCallHelpers::TrustedImm32(CallFrame::Location::encodeAsBytecodeOffset(0)),
157 CCallHelpers::tagFor(JSStack::ArgumentCount
));
158 jit
.storePtr(GPRInfo::callFrameRegister
, &vm
.topCallFrame
);
159 CCallHelpers::Call callArityCheck
= jit
.call();
161 // FIXME: need to make this call register with exception handling somehow. This is
162 // part of a bigger problem: FTL should be able to handle exceptions.
163 // https://bugs.webkit.org/show_bug.cgi?id=113622
164 // Until then, use a JIT ASSERT.
165 jit
.load64(vm
.addressOfException(), GPRInfo::regT1
);
166 jit
.jitAssertIsNull(GPRInfo::regT1
);
168 jit
.move(GPRInfo::returnValueGPR
, GPRInfo::regT0
);
169 jit
.emitFunctionEpilogue();
170 mainPathJumps
.append(jit
.branchTest32(CCallHelpers::Zero
, GPRInfo::regT0
));
171 jit
.emitFunctionPrologue();
172 jit
.move(CCallHelpers::TrustedImmPtr(vm
.arityCheckFailReturnThunks
->returnPCsFor(vm
, codeBlock
->numParameters())), GPRInfo::regT7
);
173 jit
.loadPtr(CCallHelpers::BaseIndex(GPRInfo::regT7
, GPRInfo::regT0
, CCallHelpers::timesPtr()), GPRInfo::regT7
);
174 CCallHelpers::Call callArityFixup
= jit
.call();
175 jit
.emitFunctionEpilogue();
176 mainPathJumps
.append(jit
.jump());
178 linkBuffer
= adoptPtr(new LinkBuffer(vm
, jit
, codeBlock
, JITCompilationMustSucceed
));
179 linkBuffer
->link(callArityCheck
, codeBlock
->m_isConstructor
? operationConstructArityCheck
: operationCallArityCheck
);
180 linkBuffer
->link(callArityFixup
, FunctionPtr((vm
.getCTIStub(arityFixup
)).code().executableAddress()));
181 linkBuffer
->link(mainPathJumps
, CodeLocationLabel(bitwise_cast
<void*>(state
.generatedFunction
)));
183 state
.jitCode
->initializeAddressForCall(MacroAssemblerCodePtr(bitwise_cast
<void*>(state
.generatedFunction
)));
187 case FTLForOSREntryMode
: {
188 // We jump to here straight from DFG code, after having boxed up all of the
189 // values into the scratch buffer. Everything should be good to go - at this
190 // point we've even done the stack check. Basically we just have to make the
191 // call to the LLVM-generated code.
192 CCallHelpers::Label start
= jit
.label();
193 jit
.emitFunctionEpilogue();
194 CCallHelpers::Jump mainPathJump
= jit
.jump();
196 linkBuffer
= adoptPtr(new LinkBuffer(vm
, jit
, codeBlock
, JITCompilationMustSucceed
));
197 linkBuffer
->link(mainPathJump
, CodeLocationLabel(bitwise_cast
<void*>(state
.generatedFunction
)));
199 state
.jitCode
->initializeAddressForCall(linkBuffer
->locationOf(start
));
204 RELEASE_ASSERT_NOT_REACHED();
208 state
.finalizer
->entrypointLinkBuffer
= linkBuffer
.release();
209 state
.finalizer
->function
= state
.generatedFunction
;
210 state
.finalizer
->jitCode
= state
.jitCode
;
213 } } // namespace JSC::FTL
215 #endif // ENABLE(FTL_JIT)