CallFrameShuffler64.cpp [plain text]
#include "config.h"
#include "CallFrameShuffler.h"
#if ENABLE(JIT) && USE(JSVALUE64)
#include "CCallHelpers.h"
#include "DataFormat.h"
#include "JSCInlines.h"
namespace JSC {
DataFormat CallFrameShuffler::emitStore(
CachedRecovery& cachedRecovery, MacroAssembler::Address address)
{
ASSERT(!cachedRecovery.recovery().isInJSStack());
switch (cachedRecovery.recovery().technique()) {
case InGPR:
m_jit.storePtr(cachedRecovery.recovery().gpr(), address);
return DataFormatJS;
case UnboxedInt32InGPR:
m_jit.store32(cachedRecovery.recovery().gpr(), address.withOffset(PayloadOffset));
return DataFormatInt32;
case UnboxedInt52InGPR:
m_jit.rshift64(MacroAssembler::TrustedImm32(JSValue::int52ShiftAmount),
cachedRecovery.recovery().gpr());
FALLTHROUGH;
case UnboxedStrictInt52InGPR:
m_jit.storePtr(cachedRecovery.recovery().gpr(), address);
return DataFormatStrictInt52;
case UnboxedBooleanInGPR:
m_jit.storePtr(cachedRecovery.recovery().gpr(), address);
return DataFormatBoolean;
case UnboxedCellInGPR:
m_jit.storePtr(cachedRecovery.recovery().gpr(), address);
return DataFormatCell;
case UnboxedDoubleInFPR:
m_jit.storeDouble(cachedRecovery.recovery().fpr(), address);
return DataFormatDouble;
case InFPR:
m_jit.storeDouble(cachedRecovery.recovery().fpr(), address);
return DataFormatJS;
case Constant:
m_jit.storeTrustedValue(cachedRecovery.recovery().constant(), address);
return DataFormatJS;
default:
RELEASE_ASSERT_NOT_REACHED();
}
}
void CallFrameShuffler::emitBox(CachedRecovery& cachedRecovery)
{
ASSERT(canBox(cachedRecovery));
if (cachedRecovery.recovery().isConstant())
return;
if (cachedRecovery.recovery().isInGPR()) {
switch (cachedRecovery.recovery().dataFormat()) {
case DataFormatInt32:
if (verbose)
dataLog(" * Boxing ", cachedRecovery.recovery());
m_jit.zeroExtend32ToPtr(
cachedRecovery.recovery().gpr(),
cachedRecovery.recovery().gpr());
m_lockedRegisters.set(cachedRecovery.recovery().gpr());
if (tryAcquireTagTypeNumber())
m_jit.or64(m_tagTypeNumber, cachedRecovery.recovery().gpr());
else {
m_jit.or64(MacroAssembler::TrustedImm64(TagTypeNumber),
cachedRecovery.recovery().gpr());
}
m_lockedRegisters.clear(cachedRecovery.recovery().gpr());
cachedRecovery.setRecovery(
ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatJS));
if (verbose)
dataLog(" into ", cachedRecovery.recovery(), "\n");
return;
case DataFormatInt52:
if (verbose)
dataLog(" * Boxing ", cachedRecovery.recovery());
m_jit.rshift64(MacroAssembler::TrustedImm32(JSValue::int52ShiftAmount),
cachedRecovery.recovery().gpr());
cachedRecovery.setRecovery(
ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatStrictInt52));
if (verbose)
dataLog(" into ", cachedRecovery.recovery(), "\n");
FALLTHROUGH;
case DataFormatStrictInt52: {
if (verbose)
dataLog(" * Boxing ", cachedRecovery.recovery());
FPRReg resultFPR = getFreeFPR();
ASSERT(resultFPR != InvalidFPRReg);
m_jit.convertInt64ToDouble(cachedRecovery.recovery().gpr(), resultFPR);
updateRecovery(cachedRecovery, ValueRecovery::inFPR(resultFPR, DataFormatDouble));
if (verbose)
dataLog(" into ", cachedRecovery.recovery(), "\n");
break;
}
case DataFormatBoolean:
if (verbose)
dataLog(" * Boxing ", cachedRecovery.recovery());
m_jit.add32(MacroAssembler::TrustedImm32(ValueFalse),
cachedRecovery.recovery().gpr());
cachedRecovery.setRecovery(
ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatJS));
if (verbose)
dataLog(" into ", cachedRecovery.recovery(), "\n");
return;
default:
return;
}
}
if (cachedRecovery.recovery().isInFPR()) {
if (cachedRecovery.recovery().dataFormat() == DataFormatDouble) {
if (verbose)
dataLog(" * Boxing ", cachedRecovery.recovery());
GPRReg resultGPR = cachedRecovery.wantedJSValueRegs().gpr();
if (resultGPR == InvalidGPRReg || m_registers[resultGPR])
resultGPR = getFreeGPR();
ASSERT(resultGPR != InvalidGPRReg);
m_jit.purifyNaN(cachedRecovery.recovery().fpr());
m_jit.moveDoubleTo64(cachedRecovery.recovery().fpr(), resultGPR);
m_lockedRegisters.set(resultGPR);
if (tryAcquireTagTypeNumber())
m_jit.sub64(m_tagTypeNumber, resultGPR);
else
m_jit.sub64(MacroAssembler::TrustedImm64(TagTypeNumber), resultGPR);
m_lockedRegisters.clear(resultGPR);
updateRecovery(cachedRecovery, ValueRecovery::inGPR(resultGPR, DataFormatJS));
if (verbose)
dataLog(" into ", cachedRecovery.recovery(), "\n");
return;
}
ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS);
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
void CallFrameShuffler::emitLoad(CachedRecovery& cachedRecovery)
{
if (!cachedRecovery.recovery().isInJSStack())
return;
if (verbose)
dataLog(" * Loading ", cachedRecovery.recovery(), " into ");
VirtualRegister reg = cachedRecovery.recovery().virtualRegister();
MacroAssembler::Address address { addressForOld(reg) };
bool tryFPR { true };
GPRReg resultGPR { cachedRecovery.wantedJSValueRegs().gpr() };
if (resultGPR != InvalidGPRReg && !m_registers[resultGPR]
&& !m_lockedRegisters.get(resultGPR) && cachedRecovery.loadsIntoGPR())
tryFPR = false;
if (tryFPR && cachedRecovery.loadsIntoFPR()) {
FPRReg resultFPR { cachedRecovery.wantedFPR() };
if (resultFPR == InvalidFPRReg || m_registers[resultFPR] || m_lockedRegisters.get(resultFPR))
resultFPR = getFreeFPR();
if (resultFPR != InvalidFPRReg) {
m_jit.loadDouble(address, resultFPR);
DataFormat dataFormat = DataFormatJS;
if (cachedRecovery.recovery().dataFormat() == DataFormatDouble)
dataFormat = DataFormatDouble;
updateRecovery(cachedRecovery,
ValueRecovery::inFPR(resultFPR, dataFormat));
if (verbose)
dataLog(cachedRecovery.recovery(), "\n");
if (reg == newAsOld(dangerFrontier()))
updateDangerFrontier();
return;
}
}
ASSERT(cachedRecovery.loadsIntoGPR());
if (resultGPR == InvalidGPRReg || m_registers[resultGPR] || m_lockedRegisters.get(resultGPR))
resultGPR = getFreeGPR();
ASSERT(resultGPR != InvalidGPRReg);
m_jit.loadPtr(address, resultGPR);
updateRecovery(cachedRecovery,
ValueRecovery::inGPR(resultGPR, cachedRecovery.recovery().dataFormat()));
if (verbose)
dataLog(cachedRecovery.recovery(), "\n");
if (reg == newAsOld(dangerFrontier()))
updateDangerFrontier();
}
bool CallFrameShuffler::canLoad(CachedRecovery& cachedRecovery)
{
if (!cachedRecovery.recovery().isInJSStack())
return true;
ASSERT(cachedRecovery.loadsIntoFPR() || cachedRecovery.loadsIntoGPR());
if (cachedRecovery.loadsIntoFPR() && getFreeFPR() != InvalidFPRReg)
return true;
if (cachedRecovery.loadsIntoGPR() && getFreeGPR() != InvalidGPRReg)
return true;
return false;
}
void CallFrameShuffler::emitDisplace(CachedRecovery& cachedRecovery)
{
Reg wantedReg;
if (!(wantedReg = Reg { cachedRecovery.wantedJSValueRegs().gpr() }))
wantedReg = Reg { cachedRecovery.wantedFPR() };
ASSERT(wantedReg);
ASSERT(!m_lockedRegisters.get(wantedReg));
if (CachedRecovery* current = m_registers[wantedReg]) {
if (current == &cachedRecovery) {
if (verbose)
dataLog(" + ", wantedReg, " is OK\n");
return;
}
if (wantedReg.isFPR()) {
FPRReg tempFPR = getFreeFPR();
if (verbose)
dataLog(" * Moving ", wantedReg, " into ", tempFPR, "\n");
m_jit.moveDouble(wantedReg.fpr(), tempFPR);
updateRecovery(*current,
ValueRecovery::inFPR(tempFPR, current->recovery().dataFormat()));
} else {
GPRReg tempGPR = getFreeGPR();
if (verbose)
dataLog(" * Moving ", wantedReg.gpr(), " into ", tempGPR, "\n");
m_jit.move(wantedReg.gpr(), tempGPR);
updateRecovery(*current,
ValueRecovery::inGPR(tempGPR, current->recovery().dataFormat()));
}
}
ASSERT(!m_registers[wantedReg]);
if (cachedRecovery.recovery().isConstant()) {
ASSERT(wantedReg.isGPR());
if (verbose)
dataLog(" * Loading ", cachedRecovery.recovery().constant(), " into ", wantedReg, "\n");
m_jit.moveTrustedValue(cachedRecovery.recovery().constant(), JSValueRegs { wantedReg.gpr() });
updateRecovery(
cachedRecovery,
ValueRecovery::inRegister(wantedReg, DataFormatJS));
} else if (cachedRecovery.recovery().isInGPR()) {
if (verbose)
dataLog(" * Moving ", cachedRecovery.recovery(), " into ", wantedReg, "\n");
if (wantedReg.isGPR())
m_jit.move(cachedRecovery.recovery().gpr(), wantedReg.gpr());
else
m_jit.move64ToDouble(cachedRecovery.recovery().gpr(), wantedReg.fpr());
RELEASE_ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS);
updateRecovery(cachedRecovery,
ValueRecovery::inRegister(wantedReg, DataFormatJS));
} else {
ASSERT(cachedRecovery.recovery().isInFPR());
if (cachedRecovery.recovery().dataFormat() == DataFormatDouble) {
ASSERT(wantedReg.isGPR());
emitBox(cachedRecovery);
} else {
if (verbose)
dataLog(" * Moving ", cachedRecovery.recovery().fpr(), " into ", wantedReg, "\n");
if (wantedReg.isGPR())
m_jit.moveDoubleTo64(cachedRecovery.recovery().fpr(), wantedReg.gpr());
else
m_jit.moveDouble(cachedRecovery.recovery().fpr(), wantedReg.fpr());
RELEASE_ASSERT(cachedRecovery.recovery().dataFormat() == DataFormatJS);
updateRecovery(cachedRecovery,
ValueRecovery::inRegister(wantedReg, DataFormatJS));
}
}
ASSERT(m_registers[wantedReg] == &cachedRecovery);
}
bool CallFrameShuffler::tryAcquireTagTypeNumber()
{
if (m_tagTypeNumber != InvalidGPRReg)
return true;
m_tagTypeNumber = getFreeGPR();
if (m_tagTypeNumber == InvalidGPRReg)
return false;
m_lockedRegisters.set(m_tagTypeNumber);
m_jit.move(MacroAssembler::TrustedImm64(TagTypeNumber), m_tagTypeNumber);
return true;
}
}
#endif // ENABLE(JIT) && USE(JSVALUE64)