/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "FTLLink.h"
#if ENABLE(FTL_JIT)
#include "CallFrameInlines.h"
#include "CodeBlockWithJITType.h"
#include "DFGCCallHelpers.h"
#include "DFGCommon.h"
#include "FTLJITCode.h"
#include "JITStubs.h"
#include "LinkBuffer.h"
#include
namespace JSC { namespace FTL {
using namespace DFG;
static void compileEntry(CCallHelpers& jit)
{
jit.preserveReturnAddressAfterCall(GPRInfo::regT2);
jit.emitPutToCallFrameHeader(GPRInfo::regT2, JSStack::ReturnPC);
jit.emitPutImmediateToCallFrameHeader(jit.codeBlock(), JSStack::CodeBlock);
}
void link(State& state)
{
CodeBlock* codeBlock = state.graph.m_codeBlock;
// LLVM will create its own jump tables as needed.
codeBlock->clearSwitchJumpTables();
// Create the entrypoint.
// FIXME: This is a total kludge - LLVM should just use our calling convention.
// https://bugs.webkit.org/show_bug.cgi?id=113621
CCallHelpers jit(&state.graph.m_vm, codeBlock);
compileEntry(jit);
// This part is only necessary for functions. We currently only compile functions.
CCallHelpers::Label fromArityCheck = jit.label();
// Plant a check that sufficient space is available in the JSStack.
// FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291
jit.addPtr(
CCallHelpers::TrustedImm32(codeBlock->m_numCalleeRegisters * sizeof(Register)),
GPRInfo::callFrameRegister, GPRInfo::regT1);
CCallHelpers::Jump stackCheck = jit.branchPtr(
CCallHelpers::Below,
CCallHelpers::AbsoluteAddress(state.graph.m_vm.interpreter->stack().addressOfEnd()),
GPRInfo::regT1);
CCallHelpers::Label fromStackCheck = jit.label();
jit.setupArgumentsExecState();
jit.move(CCallHelpers::TrustedImmPtr(reinterpret_cast(state.generatedFunction)), GPRInfo::nonArgGPR0);
jit.call(GPRInfo::nonArgGPR0);
jit.emitGetFromCallFrameHeaderPtr(JSStack::ReturnPC, GPRInfo::regT1);
jit.emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, GPRInfo::callFrameRegister);
jit.restoreReturnAddressBeforeReturn(GPRInfo::regT1);
jit.ret();
stackCheck.link(&jit);
jit.move(CCallHelpers::stackPointerRegister, GPRInfo::argumentGPR0);
jit.poke(
GPRInfo::callFrameRegister,
OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
jit.store32(
CCallHelpers::TrustedImm32(CallFrame::Location::encodeAsBytecodeOffset(0)),
CCallHelpers::tagFor(static_cast(JSStack::ArgumentCount)));
CCallHelpers::Call callStackCheck = jit.call();
// FIXME: need to make this call register with exception handling somehow. This is
// part of a bigger problem: FTL should be able to handle exceptions.
// https://bugs.webkit.org/show_bug.cgi?id=113622
jit.jump(fromStackCheck);
CCallHelpers::Label arityCheck = jit.label();
compileEntry(jit);
jit.load32(
CCallHelpers::payloadFor(static_cast(JSStack::ArgumentCount)),
GPRInfo::regT1);
jit.branch32(
CCallHelpers::AboveOrEqual, GPRInfo::regT1,
CCallHelpers::TrustedImm32(codeBlock->numParameters()))
.linkTo(fromArityCheck, &jit);
jit.move(CCallHelpers::stackPointerRegister, GPRInfo::argumentGPR0);
jit.poke(
GPRInfo::callFrameRegister,
OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
jit.store32(
CCallHelpers::TrustedImm32(CallFrame::Location::encodeAsBytecodeOffset(0)),
CCallHelpers::tagFor(static_cast(JSStack::ArgumentCount)));
CCallHelpers::Call callArityCheck = jit.call();
// FIXME: need to make this call register with exception handling somehow. This is
// part of a bigger problem: FTL should be able to handle exceptions.
// https://bugs.webkit.org/show_bug.cgi?id=113622
jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT0).linkTo(fromArityCheck, &jit);
CCallHelpers::Call callArityFixup = jit.call();
jit.jump(fromArityCheck);
OwnPtr linkBuffer = adoptPtr(new LinkBuffer(state.graph.m_vm, &jit, codeBlock, JITCompilationMustSucceed));
linkBuffer->link(callStackCheck, cti_stack_check);
linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);
linkBuffer->link(callArityFixup, FunctionPtr((state.graph.m_vm.getCTIStub(arityFixup)).code().executableAddress()));
state.finalizer->initializeEntrypointLinkBuffer(linkBuffer.release());
state.finalizer->initializeFunction(state.generatedFunction);
state.finalizer->initializeArityCheck(arityCheck);
state.finalizer->initializeJITCode(state.jitCode);
}
} } // namespace JSC::FTL
#endif // ENABLE(FTL_JIT)