DFGScratchRegisterAllocator.h [plain text]
#ifndef DFGScratchRegisterAllocator_h
#define DFGScratchRegisterAllocator_h
#include <wtf/Platform.h>
#if ENABLE(DFG_JIT)
#include "DFGRegisterSet.h"
#include "MacroAssembler.h"
namespace JSC { namespace DFG {
class ScratchRegisterAllocator {
public:
ScratchRegisterAllocator(const RegisterSet& usedRegisters)
: m_usedRegisters(usedRegisters)
, m_didReuseRegisters(false)
{
}
template<typename T>
void lock(T reg) { m_lockedRegisters.set(reg); }
template<typename BankInfo>
typename BankInfo::RegisterType allocateScratch()
{
for (unsigned i = 0; i < BankInfo::numberOfRegisters; ++i) {
typename BankInfo::RegisterType reg = BankInfo::toRegister(i);
if (!m_lockedRegisters.get(reg)
&& !m_usedRegisters.get(reg)
&& !m_scratchRegisters.get(reg)) {
m_scratchRegisters.set(reg);
return reg;
}
}
for (unsigned i = 0; i < BankInfo::numberOfRegisters; ++i) {
typename BankInfo::RegisterType reg = BankInfo::toRegister(i);
if (!m_lockedRegisters.get(reg) && !m_scratchRegisters.get(reg)) {
m_scratchRegisters.set(reg);
m_didReuseRegisters = true;
return reg;
}
}
CRASH();
return static_cast<typename BankInfo::RegisterType>(-1);
}
GPRReg allocateScratchGPR() { return allocateScratch<GPRInfo>(); }
FPRReg allocateScratchFPR() { return allocateScratch<FPRInfo>(); }
bool didReuseRegisters() const
{
return m_didReuseRegisters;
}
void preserveReusedRegistersByPushing(MacroAssembler& jit)
{
if (!m_didReuseRegisters)
return;
for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
if (m_scratchRegisters.getFPRByIndex(i) && m_usedRegisters.getFPRByIndex(i))
jit.pushToSave(FPRInfo::toRegister(i));
}
for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
if (m_scratchRegisters.getGPRByIndex(i) && m_usedRegisters.getGPRByIndex(i))
jit.pushToSave(GPRInfo::toRegister(i));
}
}
void restoreReusedRegistersByPopping(MacroAssembler& jit)
{
if (!m_didReuseRegisters)
return;
for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
if (m_scratchRegisters.getGPRByIndex(i) && m_usedRegisters.getGPRByIndex(i))
jit.popToRestore(GPRInfo::toRegister(i));
}
for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
if (m_scratchRegisters.getFPRByIndex(i) && m_usedRegisters.getFPRByIndex(i))
jit.popToRestore(FPRInfo::toRegister(i));
}
}
unsigned desiredScratchBufferSize() const { return m_usedRegisters.numberOfSetRegisters() * sizeof(JSValue); }
void preserveUsedRegistersToScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg)
{
unsigned count = 0;
for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
if (m_usedRegisters.getGPRByIndex(i)) {
#if USE(JSVALUE64)
jit.store64(GPRInfo::toRegister(i), static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++));
#else
jit.store32(GPRInfo::toRegister(i), static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++));
#endif
}
if (scratchGPR == InvalidGPRReg && !m_lockedRegisters.getGPRByIndex(i) && !m_scratchRegisters.getGPRByIndex(i))
scratchGPR = GPRInfo::toRegister(i);
}
RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
if (m_usedRegisters.getFPRByIndex(i)) {
jit.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++)), scratchGPR);
jit.storeDouble(FPRInfo::toRegister(i), scratchGPR);
}
}
RELEASE_ASSERT(count * sizeof(JSValue) == desiredScratchBufferSize());
jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
jit.storePtr(MacroAssembler::TrustedImmPtr(static_cast<size_t>(count * sizeof(JSValue))), scratchGPR);
}
void restoreUsedRegistersFromScratchBuffer(MacroAssembler& jit, ScratchBuffer* scratchBuffer, GPRReg scratchGPR = InvalidGPRReg)
{
if (scratchGPR == InvalidGPRReg) {
for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
if (m_lockedRegisters.getGPRByIndex(i) || m_scratchRegisters.getGPRByIndex(i))
continue;
scratchGPR = GPRInfo::toRegister(i);
break;
}
}
RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratchGPR);
jit.storePtr(MacroAssembler::TrustedImmPtr(0), scratchGPR);
unsigned count = m_usedRegisters.numberOfSetGPRs();
for (unsigned i = FPRInfo::numberOfRegisters; i--;) {
if (m_usedRegisters.getFPRByIndex(i)) {
jit.move(MacroAssembler::TrustedImmPtr(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++)), scratchGPR);
jit.loadDouble(scratchGPR, FPRInfo::toRegister(i));
}
}
count = 0;
for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
if (m_usedRegisters.getGPRByIndex(i)) {
#if USE(JSVALUE64)
jit.load64(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++), GPRInfo::toRegister(i));
#else
jit.load32(static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) + (count++), GPRInfo::toRegister(i));
#endif
}
}
}
private:
RegisterSet m_usedRegisters;
RegisterSet m_lockedRegisters;
RegisterSet m_scratchRegisters;
bool m_didReuseRegisters;
};
} }
#endif // ENABLE(DFG_JIT)
#endif // DFGScratchRegisterAllocator_h