/* | |
* Copyright (C) 2008 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. | |
*/ | |
#ifndef JITStubCall_h | |
#define JITStubCall_h | |
#include "MacroAssemblerCodeRef.h" | |
#if ENABLE(JIT) | |
namespace JSC { | |
class JITStubCall { | |
public: | |
JITStubCall(JIT* jit, JSObject* (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) | |
: m_jit(jit) | |
, m_stub(stub) | |
, m_returnType(Cell) | |
, m_stackIndex(JITSTACKFRAME_ARGS_INDEX) | |
{ | |
} | |
JITStubCall(JIT* jit, JSPropertyNameIterator* (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) | |
: m_jit(jit) | |
, m_stub(stub) | |
, m_returnType(Cell) | |
, m_stackIndex(JITSTACKFRAME_ARGS_INDEX) | |
{ | |
} | |
JITStubCall(JIT* jit, void* (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) | |
: m_jit(jit) | |
, m_stub(stub) | |
, m_returnType(VoidPtr) | |
, m_stackIndex(JITSTACKFRAME_ARGS_INDEX) | |
{ | |
} | |
JITStubCall(JIT* jit, int (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) | |
: m_jit(jit) | |
, m_stub(stub) | |
, m_returnType(Int) | |
, m_stackIndex(JITSTACKFRAME_ARGS_INDEX) | |
{ | |
} | |
JITStubCall(JIT* jit, bool (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) | |
: m_jit(jit) | |
, m_stub(stub) | |
, m_returnType(Int) | |
, m_stackIndex(JITSTACKFRAME_ARGS_INDEX) | |
{ | |
} | |
JITStubCall(JIT* jit, void (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) | |
: m_jit(jit) | |
, m_stub(stub) | |
, m_returnType(Void) | |
, m_stackIndex(JITSTACKFRAME_ARGS_INDEX) | |
{ | |
} | |
#if USE(JSVALUE32_64) | |
JITStubCall(JIT* jit, EncodedJSValue (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) | |
: m_jit(jit) | |
, m_stub(stub) | |
, m_returnType(Value) | |
, m_stackIndex(JITSTACKFRAME_ARGS_INDEX) | |
{ | |
} | |
#endif | |
// Arguments are added first to last. | |
void skipArgument() | |
{ | |
m_stackIndex += stackIndexStep; | |
} | |
void addArgument(JIT::Imm32 argument) | |
{ | |
m_jit->poke(argument, m_stackIndex); | |
m_stackIndex += stackIndexStep; | |
} | |
void addArgument(JIT::ImmPtr argument) | |
{ | |
m_jit->poke(argument, m_stackIndex); | |
m_stackIndex += stackIndexStep; | |
} | |
void addArgument(JIT::RegisterID argument) | |
{ | |
m_jit->poke(argument, m_stackIndex); | |
m_stackIndex += stackIndexStep; | |
} | |
void addArgument(const JSValue& value) | |
{ | |
m_jit->poke(JIT::Imm32(value.payload()), m_stackIndex); | |
m_jit->poke(JIT::Imm32(value.tag()), m_stackIndex + 1); | |
m_stackIndex += stackIndexStep; | |
} | |
void addArgument(JIT::RegisterID tag, JIT::RegisterID payload) | |
{ | |
m_jit->poke(payload, m_stackIndex); | |
m_jit->poke(tag, m_stackIndex + 1); | |
m_stackIndex += stackIndexStep; | |
} | |
#if USE(JSVALUE32_64) | |
void addArgument(unsigned srcVirtualRegister) | |
{ | |
if (m_jit->m_codeBlock->isConstantRegisterIndex(srcVirtualRegister)) { | |
addArgument(m_jit->getConstantOperand(srcVirtualRegister)); | |
return; | |
} | |
m_jit->emitLoad(srcVirtualRegister, JIT::regT1, JIT::regT0); | |
addArgument(JIT::regT1, JIT::regT0); | |
} | |
void getArgument(size_t argumentNumber, JIT::RegisterID tag, JIT::RegisterID payload) | |
{ | |
size_t stackIndex = JITSTACKFRAME_ARGS_INDEX + (argumentNumber * stackIndexStep); | |
m_jit->peek(payload, stackIndex); | |
m_jit->peek(tag, stackIndex + 1); | |
} | |
#else | |
void addArgument(unsigned src, JIT::RegisterID scratchRegister) // src is a virtual register. | |
{ | |
if (m_jit->m_codeBlock->isConstantRegisterIndex(src)) | |
addArgument(JIT::ImmPtr(JSValue::encode(m_jit->m_codeBlock->getConstant(src)))); | |
else { | |
m_jit->loadPtr(JIT::Address(JIT::callFrameRegister, src * sizeof(Register)), scratchRegister); | |
addArgument(scratchRegister); | |
} | |
m_jit->killLastResultRegister(); | |
} | |
#endif | |
JIT::Call call() | |
{ | |
#if ENABLE(OPCODE_SAMPLING) | |
if (m_jit->m_bytecodeIndex != (unsigned)-1) | |
m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeIndex, true); | |
#endif | |
m_jit->restoreArgumentReference(); | |
JIT::Call call = m_jit->call(); | |
m_jit->m_calls.append(CallRecord(call, m_jit->m_bytecodeIndex, m_stub.value())); | |
#if ENABLE(OPCODE_SAMPLING) | |
if (m_jit->m_bytecodeIndex != (unsigned)-1) | |
m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeIndex, false); | |
#endif | |
#if USE(JSVALUE32_64) | |
m_jit->unmap(); | |
#else | |
m_jit->killLastResultRegister(); | |
#endif | |
return call; | |
} | |
#if USE(JSVALUE32_64) | |
JIT::Call call(unsigned dst) // dst is a virtual register. | |
{ | |
ASSERT(m_returnType == Value || m_returnType == Cell); | |
JIT::Call call = this->call(); | |
if (m_returnType == Value) | |
m_jit->emitStore(dst, JIT::regT1, JIT::regT0); | |
else | |
m_jit->emitStoreCell(dst, JIT::returnValueRegister); | |
return call; | |
} | |
#else | |
JIT::Call call(unsigned dst) // dst is a virtual register. | |
{ | |
ASSERT(m_returnType == VoidPtr || m_returnType == Cell); | |
JIT::Call call = this->call(); | |
m_jit->emitPutVirtualRegister(dst); | |
return call; | |
} | |
#endif | |
JIT::Call call(JIT::RegisterID dst) // dst is a machine register. | |
{ | |
#if USE(JSVALUE32_64) | |
ASSERT(m_returnType == Value || m_returnType == VoidPtr || m_returnType == Int || m_returnType == Cell); | |
#else | |
ASSERT(m_returnType == VoidPtr || m_returnType == Int || m_returnType == Cell); | |
#endif | |
JIT::Call call = this->call(); | |
if (dst != JIT::returnValueRegister) | |
m_jit->move(JIT::returnValueRegister, dst); | |
return call; | |
} | |
private: | |
static const size_t stackIndexStep = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 2 : 1; | |
JIT* m_jit; | |
FunctionPtr m_stub; | |
enum { Void, VoidPtr, Int, Value, Cell } m_returnType; | |
size_t m_stackIndex; | |
}; | |
} | |
#endif // ENABLE(JIT) | |
#endif // JITStubCall_h |