#include "CodeBlock.h"
#include "DFGJITCodeGenerator.h"
-#include "DFGNonSpeculativeJIT.h"
#include "DFGOperations.h"
#include "DFGRegisterBank.h"
#include "DFGSpeculativeJIT.h"
{
Node& node = graph()[nodeIndex];
- if (node.isConstant()) {
+ if (node.hasConstant()) {
ASSERT(isNumberConstant(nodeIndex));
move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfNumberConstant(nodeIndex)))), temporary);
movePtrToDouble(temporary, fpr);
{
Node& node = graph()[nodeIndex];
- if (node.isConstant()) {
+ if (node.hasConstant()) {
ASSERT(isInt32Constant(nodeIndex));
move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
} else {
{
Node& node = graph()[nodeIndex];
- if (node.isConstant()) {
+ if (node.hasConstant()) {
if (isInt32Constant(nodeIndex)) {
JSValue jsValue = jsNumber(valueOfInt32Constant(nodeIndex));
move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
loadPtr(addressFor(node.virtualRegister()), gpr);
}
-#if ENABLE(DFG_OSR_EXIT)
void JITCompiler::exitSpeculativeWithOSR(const OSRExit& exit, SpeculationRecovery* recovery, Vector<BytecodeAndMachineOffset>& decodedCodeMap)
{
// 1) Pro-forma stuff.
++exitsIter;
}
}
-#else // ENABLE(DFG_OSR_EXIT)
-class GeneralizedRegister {
-public:
- GeneralizedRegister() { }
-
- static GeneralizedRegister createGPR(GPRReg gpr)
- {
- GeneralizedRegister result;
- result.m_isFPR = false;
- result.m_register.gpr = gpr;
- return result;
- }
-
- static GeneralizedRegister createFPR(FPRReg fpr)
- {
- GeneralizedRegister result;
- result.m_isFPR = true;
- result.m_register.fpr = fpr;
- return result;
- }
-
- bool isFPR() const
- {
- return m_isFPR;
- }
-
- GPRReg gpr() const
- {
- ASSERT(!m_isFPR);
- return m_register.gpr;
- }
-
- FPRReg fpr() const
- {
- ASSERT(m_isFPR);
- return m_register.fpr;
- }
-
- const SpeculationCheck::RegisterInfo& findInSpeculationCheck(const SpeculationCheck& check)
- {
- if (isFPR())
- return check.m_fprInfo[FPRInfo::toIndex(fpr())];
- return check.m_gprInfo[GPRInfo::toIndex(gpr())];
- }
-
- const EntryLocation::RegisterInfo& findInEntryLocation(const EntryLocation& entry)
- {
- if (isFPR())
- return entry.m_fprInfo[FPRInfo::toIndex(fpr())];
- return entry.m_gprInfo[GPRInfo::toIndex(gpr())];
- }
-
- DataFormat previousDataFormat(const SpeculationCheck& check)
- {
- return findInSpeculationCheck(check).format;
- }
-
- DataFormat nextDataFormat(const EntryLocation& entry)
- {
- return findInEntryLocation(entry).format;
- }
-
- void convert(DataFormat oldDataFormat, DataFormat newDataFormat, JITCompiler& jit)
- {
- if (LIKELY(!needDataFormatConversion(oldDataFormat, newDataFormat)))
- return;
-
- if (oldDataFormat == DataFormatInteger) {
- jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr());
- return;
- }
-
- ASSERT(newDataFormat == DataFormatInteger);
- jit.zeroExtend32ToPtr(gpr(), gpr());
- return;
- }
-
- void moveTo(GeneralizedRegister& other, DataFormat myDataFormat, DataFormat otherDataFormat, JITCompiler& jit, FPRReg scratchFPR)
- {
- if (UNLIKELY(isFPR())) {
- if (UNLIKELY(other.isFPR())) {
- jit.moveDouble(fpr(), other.fpr());
- return;
- }
-
- JITCompiler::Jump done;
-
- if (scratchFPR != InvalidFPRReg) {
- // we have a scratch FPR, so attempt a conversion to int
- JITCompiler::JumpList notInt;
- jit.branchConvertDoubleToInt32(fpr(), other.gpr(), notInt, scratchFPR);
- jit.orPtr(GPRInfo::tagTypeNumberRegister, other.gpr());
- done = jit.jump();
- notInt.link(&jit);
- }
-
- jit.boxDouble(fpr(), other.gpr());
-
- if (done.isSet())
- done.link(&jit);
- return;
- }
-
- if (UNLIKELY(other.isFPR())) {
- jit.unboxDouble(gpr(), other.fpr());
- return;
- }
-
- if (LIKELY(!needDataFormatConversion(myDataFormat, otherDataFormat))) {
- jit.move(gpr(), other.gpr());
- return;
- }
-
- if (myDataFormat == DataFormatInteger) {
- jit.orPtr(gpr(), GPRInfo::tagTypeNumberRegister, other.gpr());
- return;
- }
-
- ASSERT(otherDataFormat == DataFormatInteger);
- jit.zeroExtend32ToPtr(gpr(), other.gpr());
- }
-
- void swapWith(GeneralizedRegister& other, DataFormat myDataFormat, DataFormat myNewDataFormat, DataFormat otherDataFormat, DataFormat otherNewDataFormat, JITCompiler& jit, GPRReg scratchGPR, FPRReg scratchFPR)
- {
- if (UNLIKELY(isFPR())) {
- if (UNLIKELY(other.isFPR())) {
- if (scratchFPR == InvalidFPRReg)
- jit.moveDoubleToPtr(fpr(), scratchGPR);
- else
- jit.moveDouble(fpr(), scratchFPR);
- jit.moveDouble(other.fpr(), fpr());
- if (scratchFPR == InvalidFPRReg)
- jit.movePtrToDouble(scratchGPR, other.fpr());
- else
- jit.moveDouble(scratchFPR, other.fpr());
- return;
- }
-
- jit.move(other.gpr(), scratchGPR);
-
- JITCompiler::Jump done;
-
- if (scratchFPR != InvalidFPRReg) {
- JITCompiler::JumpList notInt;
- jit.branchConvertDoubleToInt32(fpr(), other.gpr(), notInt, scratchFPR);
- jit.orPtr(GPRInfo::tagTypeNumberRegister, other.gpr());
- done = jit.jump();
- notInt.link(&jit);
- }
-
- jit.boxDouble(fpr(), other.gpr());
-
- if (done.isSet())
- done.link(&jit);
-
- jit.unboxDouble(scratchGPR, fpr());
- return;
- }
-
- if (UNLIKELY(other.isFPR())) {
- other.swapWith(*this, otherDataFormat, otherNewDataFormat, myDataFormat, myNewDataFormat, jit, scratchGPR, scratchFPR);
- return;
- }
-
- jit.swap(gpr(), other.gpr());
-
- if (UNLIKELY(needDataFormatConversion(otherDataFormat, myNewDataFormat))) {
- if (otherDataFormat == DataFormatInteger)
- jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr());
- else if (myNewDataFormat == DataFormatInteger)
- jit.zeroExtend32ToPtr(gpr(), gpr());
- }
-
- if (UNLIKELY(needDataFormatConversion(myDataFormat, otherNewDataFormat))) {
- if (myDataFormat == DataFormatInteger)
- jit.orPtr(GPRInfo::tagTypeNumberRegister, other.gpr());
- else if (otherNewDataFormat == DataFormatInteger)
- jit.zeroExtend32ToPtr(other.gpr(), other.gpr());
- }
- }
-
-private:
- bool m_isFPR;
- union {
- GPRReg gpr;
- FPRReg fpr;
- } m_register;
-};
-
-struct ShuffledRegister {
- GeneralizedRegister reg;
- ShuffledRegister* previous;
- bool hasFrom;
- bool hasTo;
- bool handled;
-
- ShuffledRegister() { }
-
- ShuffledRegister(GeneralizedRegister reg)
- : reg(reg)
- , previous(0)
- , hasFrom(false)
- , hasTo(false)
- , handled(false)
- {
- }
-
- bool isEndOfNonCyclingPermutation()
- {
- return hasTo && !hasFrom;
- }
-
- void handleNonCyclingPermutation(const SpeculationCheck& check, const EntryLocation& entry, JITCompiler& jit, FPRReg& scratchFPR1, FPRReg& scratchFPR2)
- {
- ShuffledRegister* cur = this;
- while (cur->previous) {
- cur->previous->reg.moveTo(cur->reg, cur->previous->reg.previousDataFormat(check), cur->reg.nextDataFormat(entry), jit, scratchFPR1);
- cur->handled = true;
- if (cur->reg.isFPR()) {
- if (scratchFPR1 == InvalidFPRReg)
- scratchFPR1 = cur->reg.fpr();
- else {
- ASSERT(scratchFPR1 != cur->reg.fpr());
- scratchFPR2 = cur->reg.fpr();
- }
- }
- cur = cur->previous;
- }
- cur->handled = true;
- if (cur->reg.isFPR()) {
- if (scratchFPR1 == InvalidFPRReg)
- scratchFPR1 = cur->reg.fpr();
- else {
- ASSERT(scratchFPR1 != cur->reg.fpr());
- scratchFPR2 = cur->reg.fpr();
- }
- }
- }
-
- void handleCyclingPermutation(const SpeculationCheck& check, const EntryLocation& entry, JITCompiler& jit, GPRReg scratchGPR, FPRReg scratchFPR1, FPRReg scratchFPR2)
- {
- // first determine the cycle length
-
- unsigned cycleLength = 0;
-
- ShuffledRegister* cur = this;
- ShuffledRegister* next = 0;
- do {
- ASSERT(cur);
- cycleLength++;
- cur->handled = true;
- next = cur;
- cur = cur->previous;
- } while (cur != this);
-
- ASSERT(cycleLength);
- ASSERT(next->previous == cur);
-
- // now determine the best way to handle the permutation, depending on the
- // length.
-
- switch (cycleLength) {
- case 1:
- reg.convert(reg.previousDataFormat(check), reg.nextDataFormat(entry), jit);
- break;
-
- case 2:
- reg.swapWith(previous->reg, reg.previousDataFormat(check), reg.nextDataFormat(entry), previous->reg.previousDataFormat(check), previous->reg.nextDataFormat(entry), jit, scratchGPR, scratchFPR1);
- break;
-
- default:
- GeneralizedRegister scratch;
- if (UNLIKELY(reg.isFPR() && next->reg.isFPR())) {
- if (scratchFPR2 == InvalidFPRReg) {
- scratch = GeneralizedRegister::createGPR(scratchGPR);
- reg.moveTo(scratch, DataFormatDouble, DataFormatJSDouble, jit, scratchFPR1);
- } else {
- scratch = GeneralizedRegister::createFPR(scratchFPR2);
- reg.moveTo(scratch, DataFormatDouble, DataFormatDouble, jit, scratchFPR1);
- }
- } else {
- scratch = GeneralizedRegister::createGPR(scratchGPR);
- reg.moveTo(scratch, reg.previousDataFormat(check), next->reg.nextDataFormat(entry), jit, scratchFPR1);
- }
-
- cur = this;
- while (cur->previous != this) {
- ASSERT(cur);
- cur->previous->reg.moveTo(cur->reg, cur->previous->reg.previousDataFormat(check), cur->reg.nextDataFormat(entry), jit, scratchFPR1);
- cur = cur->previous;
- }
-
- if (UNLIKELY(reg.isFPR() && next->reg.isFPR())) {
- if (scratchFPR2 == InvalidFPRReg)
- scratch.moveTo(next->reg, DataFormatJSDouble, DataFormatDouble, jit, scratchFPR1);
- else
- scratch.moveTo(next->reg, DataFormatDouble, DataFormatDouble, jit, scratchFPR1);
- } else
- scratch.moveTo(next->reg, next->reg.nextDataFormat(entry), next->reg.nextDataFormat(entry), jit, scratchFPR1);
- break;
- }
- }
-
- static ShuffledRegister* lookup(ShuffledRegister* gprs, ShuffledRegister* fprs, GeneralizedRegister& reg)
- {
- if (reg.isFPR())
- return fprs + FPRInfo::toIndex(reg.fpr());
- return gprs + GPRInfo::toIndex(reg.gpr());
- }
-};
-
-template<typename T>
-T& lookupForRegister(T* gprs, T* fprs, unsigned index)
-{
- ASSERT(index < GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters);
- if (index < GPRInfo::numberOfRegisters)
- return gprs[index];
- return fprs[index - GPRInfo::numberOfRegisters];
-}
-
-// This is written in a way that allows for a HashMap<NodeIndex, GeneralizedRegister> to be
-// easily substituted, if it is found to be wise to do so. So far performance measurements
-// indicate that this is faster, likely because the HashMap would have never grown very big
-// and we would thus be wasting time performing complex hashing logic that, though O(1) on
-// average, would be less than the ~7 loop iterations that the find() method below would do
-// (since it's uncommon that we'd have register allocated more than 7 registers, in the
-// current scheme).
-class NodeToRegisterMap {
-public:
- struct Tuple {
- NodeIndex first;
- GeneralizedRegister second;
-
- Tuple()
- {
- }
- };
-
- typedef Tuple* iterator;
-
- NodeToRegisterMap()
- : m_occupancy(0)
- {
- }
-
- void set(NodeIndex first, GeneralizedRegister second)
- {
- m_payload[m_occupancy].first = first;
- m_payload[m_occupancy].second = second;
- m_occupancy++;
- }
-
- Tuple* end()
- {
- return 0;
- }
-
- Tuple* find(NodeIndex first)
- {
- for (unsigned i = m_occupancy; i-- > 0;) {
- if (m_payload[i].first == first)
- return m_payload + i;
- }
- return 0;
- }
-
- void clear()
- {
- m_occupancy = 0;
- }
-
-private:
- Tuple m_payload[GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters];
- unsigned m_occupancy;
-};
-
-void JITCompiler::jumpFromSpeculativeToNonSpeculative(const SpeculationCheck& check, const EntryLocation& entry, SpeculationRecovery* recovery, NodeToRegisterMap& checkNodeToRegisterMap, NodeToRegisterMap& entryNodeToRegisterMap)
-{
- ASSERT(check.m_nodeIndex == entry.m_nodeIndex);
-
- // Link the jump from the Speculative path to here.
- check.m_check.link(this);
-
-#if ENABLE(DFG_DEBUG_VERBOSE)
- fprintf(stderr, "Speculation failure for Node @%d at JIT offset 0x%x\n", (int)check.m_nodeIndex, debugOffset());
-#endif
-#if ENABLE(DFG_JIT_BREAK_ON_SPECULATION_FAILURE)
- breakpoint();
-#endif
-
-#if ENABLE(DFG_VERBOSE_SPECULATION_FAILURE)
- SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo;
- debugInfo->codeBlock = m_codeBlock;
- debugInfo->debugOffset = debugOffset();
-
- debugCall(debugOperationPrintSpeculationFailure, debugInfo);
-#endif
-
-#if ENABLE(DFG_SUCCESS_STATS)
- static SamplingCounter counter("SpeculationFailure");
- emitCount(counter);
-#endif
-
- // Does this speculation check require any additional recovery to be performed,
- // to restore any state that has been overwritten before we enter back in to the
- // non-speculative path.
- if (recovery) {
- switch (recovery->type()) {
- case SpeculativeAdd: {
- ASSERT(check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].nodeIndex != NoNode);
- // Revert the add.
- sub32(recovery->src(), recovery->dest());
-
- // If recovery->dest() should have been boxed prior to the addition, then rebox
- // it.
- DataFormat format = check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].format;
- ASSERT(format == DataFormatInteger || format == DataFormatJSInteger || format == DataFormatJS);
- if (format != DataFormatInteger)
- orPtr(GPRInfo::tagTypeNumberRegister, recovery->dest());
- break;
- }
-
- case BooleanSpeculationCheck: {
- ASSERT(check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].nodeIndex != NoNode);
- // Rebox the (non-)boolean
- xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), recovery->dest());
- break;
- }
-
- default:
- ASSERT_NOT_REACHED();
- break;
- }
- }
-
- // First, we need a reverse mapping that tells us, for a NodeIndex, which register
- // that node is in.
-
- checkNodeToRegisterMap.clear();
- entryNodeToRegisterMap.clear();
-
- GPRReg scratchGPR = InvalidGPRReg;
- FPRReg scratchFPR1 = InvalidFPRReg;
- FPRReg scratchFPR2 = InvalidFPRReg;
- bool needToRestoreTagMaskRegister = false;
-
- for (unsigned index = 0; index < GPRInfo::numberOfRegisters; ++index) {
- NodeIndex nodeIndexInCheck = check.m_gprInfo[index].nodeIndex;
- if (nodeIndexInCheck != NoNode)
- checkNodeToRegisterMap.set(nodeIndexInCheck, GeneralizedRegister::createGPR(GPRInfo::toRegister(index)));
- NodeIndex nodeIndexInEntry = entry.m_gprInfo[index].nodeIndex;
- if (nodeIndexInEntry != NoNode)
- entryNodeToRegisterMap.set(nodeIndexInEntry, GeneralizedRegister::createGPR(GPRInfo::toRegister(index)));
- else if (nodeIndexInCheck == NoNode)
- scratchGPR = GPRInfo::toRegister(index);
- }
-
- for (unsigned index = 0; index < FPRInfo::numberOfRegisters; ++index) {
- NodeIndex nodeIndexInCheck = check.m_fprInfo[index].nodeIndex;
- if (nodeIndexInCheck != NoNode)
- checkNodeToRegisterMap.set(nodeIndexInCheck, GeneralizedRegister::createFPR(FPRInfo::toRegister(index)));
- NodeIndex nodeIndexInEntry = entry.m_fprInfo[index].nodeIndex;
- if (nodeIndexInEntry != NoNode)
- entryNodeToRegisterMap.set(nodeIndexInEntry, GeneralizedRegister::createFPR(FPRInfo::toRegister(index)));
- else if (nodeIndexInCheck == NoNode) {
- if (scratchFPR1 == InvalidFPRReg)
- scratchFPR1 = FPRInfo::toRegister(index);
- else
- scratchFPR2 = FPRInfo::toRegister(index);
- }
- }
-
- ASSERT((scratchFPR1 == InvalidFPRReg && scratchFPR2 == InvalidFPRReg) || (scratchFPR1 != scratchFPR2));
-
- // How this works:
- // 1) Spill any values that are not spilled on speculative, but are spilled
- // on non-speculative.
- // 2) For the set of nodes that are in registers on both paths, perform a
- // shuffling.
- // 3) Fill any values that were spilled on speculative, but are not spilled
- // on non-speculative.
-
- // If we find registers that can be used as scratch registers along the way,
- // save them.
-
- // Part 1: spill any values that are not spilled on speculative, but are
- // spilled on non-speculative.
-
- // This also sets up some data structures that Part 2 will need.
-
- ShuffledRegister gprs[GPRInfo::numberOfRegisters];
- ShuffledRegister fprs[FPRInfo::numberOfRegisters];
-
- for (unsigned index = 0; index < GPRInfo::numberOfRegisters; ++index)
- gprs[index] = ShuffledRegister(GeneralizedRegister::createGPR(GPRInfo::toRegister(index)));
- for (unsigned index = 0; index < FPRInfo::numberOfRegisters; ++index)
- fprs[index] = ShuffledRegister(GeneralizedRegister::createFPR(FPRInfo::toRegister(index)));
-
- for (unsigned index = 0; index < GPRInfo::numberOfRegisters; ++index) {
- NodeIndex nodeIndex = check.m_gprInfo[index].nodeIndex;
-
- // Bail out if this register isn't assigned to anything.
- if (nodeIndex == NoNode)
- continue;
-
- // If the non-speculative path also has a register for the nodeIndex that this
- // register stores, link them together.
- NodeToRegisterMap::iterator mapIterator = entryNodeToRegisterMap.find(nodeIndex);
- if (mapIterator != entryNodeToRegisterMap.end()) {
- gprs[index].hasFrom = true;
-
- ShuffledRegister* next = ShuffledRegister::lookup(gprs, fprs, mapIterator->second);
- next->previous = gprs + index;
- next->hasTo = true;
-
- // If the non-speculative path has not spilled this register, then skip the spillin
- // part below regardless of whether or not the speculative path has spilled it.
- if (!mapIterator->second.findInEntryLocation(entry).isSpilled)
- continue;
- } else {
- // If the non-speculative entry isn't using this register and it does not need
- // the value in this register to be placed into any other register, then this
- // register can be used for scratch.
- if (entry.m_gprInfo[index].nodeIndex == NoNode)
- scratchGPR = GPRInfo::toRegister(index);
- }
-
- // If the speculative path has already spilled the register then there is no need to
- // spill it.
- if (check.m_gprInfo[index].isSpilled)
- continue;
-
- DataFormat dataFormat = check.m_gprInfo[index].format;
- VirtualRegister virtualRegister = graph()[nodeIndex].virtualRegister();
-
- ASSERT(dataFormat == DataFormatInteger || DataFormatCell || dataFormat & DataFormatJS);
- if (dataFormat == DataFormatInteger)
- orPtr(GPRInfo::tagTypeNumberRegister, GPRInfo::toRegister(index));
- storePtr(GPRInfo::toRegister(index), addressFor(virtualRegister));
- }
-
- if (scratchGPR == InvalidGPRReg) {
- scratchGPR = GPRInfo::tagMaskRegister;
- needToRestoreTagMaskRegister = true;
- }
-
- for (unsigned index = 0; index < FPRInfo::numberOfRegisters; ++index) {
- NodeIndex nodeIndex = check.m_fprInfo[index].nodeIndex;
- if (nodeIndex == NoNode)
- continue;
-
- NodeToRegisterMap::iterator mapIterator = entryNodeToRegisterMap.find(nodeIndex);
- if (mapIterator != entryNodeToRegisterMap.end()) {
- fprs[index].hasFrom = true;
-
- ShuffledRegister* next = ShuffledRegister::lookup(gprs, fprs, mapIterator->second);
- next->previous = fprs + index;
- next->hasTo = true;
-
- if (!mapIterator->second.findInEntryLocation(entry).isSpilled)
- continue;
- } else {
- // If the non-speculative entry isn't using this register and it does not need
- // the value in this register to be placed into any other register, then this
- // register can be used for scratch.
- if (entry.m_fprInfo[index].nodeIndex == NoNode) {
- if (scratchFPR1 == InvalidFPRReg)
- scratchFPR1 = FPRInfo::toRegister(index);
- else if (scratchFPR2)
- scratchFPR2 = FPRInfo::toRegister(index);
- ASSERT((scratchFPR1 == InvalidFPRReg && scratchFPR2 == InvalidFPRReg) || (scratchFPR1 != scratchFPR2));
- }
- }
-
- if (check.m_fprInfo[index].isSpilled)
- continue;
-
- VirtualRegister virtualRegister = graph()[nodeIndex].virtualRegister();
-
- moveDoubleToPtr(FPRInfo::toRegister(index), scratchGPR);
- subPtr(GPRInfo::tagTypeNumberRegister, scratchGPR);
- storePtr(scratchGPR, addressFor(virtualRegister));
- }
-
-#if !ASSERT_DISABLED
- // Assert that we've not assigned a scratch register to something that we're going to shuffle.
- ASSERT(scratchGPR != InvalidGPRReg);
- if (scratchGPR != GPRInfo::tagMaskRegister) {
- ASSERT(!gprs[GPRInfo::toIndex(scratchGPR)].hasTo);
- ASSERT(!gprs[GPRInfo::toIndex(scratchGPR)].hasFrom);
- }
- if (scratchFPR1 != InvalidFPRReg) {
- ASSERT(scratchFPR1 != scratchFPR2);
- ASSERT(!fprs[FPRInfo::toIndex(scratchFPR1)].hasTo);
- ASSERT(!fprs[FPRInfo::toIndex(scratchFPR1)].hasFrom);
- if (scratchFPR2 != InvalidFPRReg) {
- ASSERT(!fprs[FPRInfo::toIndex(scratchFPR2)].hasTo);
- ASSERT(!fprs[FPRInfo::toIndex(scratchFPR2)].hasFrom);
- }
- } else
- ASSERT(scratchFPR2 == InvalidFPRReg);
-#endif
-
- // Part 2: For the set of nodes that are in registers on both paths,
- // perform a shuffling.
-
- for (unsigned index = 0; index < GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters; ++index) {
- ShuffledRegister& reg = lookupForRegister(gprs, fprs, index);
- if (!reg.isEndOfNonCyclingPermutation() || reg.handled || (!reg.hasFrom && !reg.hasTo))
- continue;
-
- reg.handleNonCyclingPermutation(check, entry, *this, scratchFPR1, scratchFPR2);
- ASSERT((scratchFPR1 == InvalidFPRReg && scratchFPR2 == InvalidFPRReg) || (scratchFPR1 != scratchFPR2));
- }
-
- for (unsigned index = 0; index < GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters; ++index) {
- ShuffledRegister& reg = lookupForRegister(gprs, fprs, index);
- if (reg.handled || (!reg.hasFrom && !reg.hasTo))
- continue;
-
- reg.handleCyclingPermutation(check, entry, *this, scratchGPR, scratchFPR1, scratchFPR2);
- ASSERT((scratchFPR1 == InvalidFPRReg && scratchFPR2 == InvalidFPRReg) || (scratchFPR1 != scratchFPR2));
- }
-
-#if !ASSERT_DISABLED
- for (unsigned index = 0; index < GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters; ++index) {
- ShuffledRegister& reg = lookupForRegister(gprs, fprs, index);
- ASSERT(reg.handled || (!reg.hasFrom && !reg.hasTo));
- }
-#endif
-
- // Part 3: Fill any values that were spilled on speculative, but are not spilled
- // on non-speculative.
-
- for (unsigned index = 0; index < FPRInfo::numberOfRegisters; ++index) {
- NodeIndex nodeIndex = entry.m_fprInfo[index].nodeIndex;
- if (nodeIndex == NoNode || entry.m_fprInfo[index].isSpilled)
- continue;
-
- NodeToRegisterMap::iterator mapIterator = checkNodeToRegisterMap.find(nodeIndex);
- if (mapIterator != checkNodeToRegisterMap.end()
- && !mapIterator->second.findInSpeculationCheck(check).isSpilled)
- continue;
-
- fillNumericToDouble(nodeIndex, FPRInfo::toRegister(index), GPRInfo::regT0);
- }
-
- for (unsigned index = 0; index < GPRInfo::numberOfRegisters; ++index) {
- NodeIndex nodeIndex = entry.m_gprInfo[index].nodeIndex;
- if (nodeIndex == NoNode || entry.m_gprInfo[index].isSpilled)
- continue;
-
- NodeToRegisterMap::iterator mapIterator = checkNodeToRegisterMap.find(nodeIndex);
- if (mapIterator != checkNodeToRegisterMap.end()
- && !mapIterator->second.findInSpeculationCheck(check).isSpilled)
- continue;
-
- DataFormat dataFormat = entry.m_gprInfo[index].format;
- if (dataFormat == DataFormatInteger)
- fillInt32ToInteger(nodeIndex, GPRInfo::toRegister(index));
- else {
- ASSERT(dataFormat & DataFormatJS || dataFormat == DataFormatCell); // Treat cell as JSValue for now!
- fillToJS(nodeIndex, GPRInfo::toRegister(index));
- // FIXME: For subtypes of DataFormatJS, should jitAssert the subtype?
- }
- }
-
- if (needToRestoreTagMaskRegister)
- move(TrustedImmPtr(reinterpret_cast<void*>(TagMask)), GPRInfo::tagMaskRegister);
-
- // Jump into the non-speculative path.
- jump(entry.m_entry);
-}
-
-void JITCompiler::linkSpeculationChecks(SpeculativeJIT& speculative, NonSpeculativeJIT& nonSpeculative)
-{
- // Iterators to walk over the set of bail outs & corresponding entry points.
- SpeculationCheckVector::Iterator checksIter = speculative.speculationChecks().begin();
- SpeculationCheckVector::Iterator checksEnd = speculative.speculationChecks().end();
- NonSpeculativeJIT::EntryLocationVector::Iterator entriesIter = nonSpeculative.entryLocations().begin();
- NonSpeculativeJIT::EntryLocationVector::Iterator entriesEnd = nonSpeculative.entryLocations().end();
-
- NodeToRegisterMap checkNodeToRegisterMap;
- NodeToRegisterMap entryNodeToRegisterMap;
-
- // Iterate over the speculation checks.
- while (checksIter != checksEnd) {
- // For every bail out from the speculative path, we must have provided an entry point
- // into the non-speculative one.
- ASSERT(checksIter->m_nodeIndex == entriesIter->m_nodeIndex);
-
- // There may be multiple bail outs that map to the same entry point!
- do {
- ASSERT(checksIter != checksEnd);
- ASSERT(entriesIter != entriesEnd);
-
- // Plant code to link this speculation failure.
- const SpeculationCheck& check = *checksIter;
- const EntryLocation& entry = *entriesIter;
- jumpFromSpeculativeToNonSpeculative(check, entry, speculative.speculationRecovery(check.m_recoveryIndex), checkNodeToRegisterMap, entryNodeToRegisterMap);
- ++checksIter;
- } while (checksIter != checksEnd && checksIter->m_nodeIndex == entriesIter->m_nodeIndex);
- ++entriesIter;
- }
-
- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56289
- ASSERT(!(checksIter != checksEnd));
- ASSERT(!(entriesIter != entriesEnd));
-}
-#endif // ENABLE(DFG_OSR_EXIT)
void JITCompiler::compileEntry()
{
void JITCompiler::compileBody()
{
- // We generate the speculative code path, followed by the non-speculative
- // code for the function. Next we need to link the two together, making
- // bail-outs from the speculative path jump to the corresponding point on
- // the non-speculative one (and generating any code necessary to juggle
- // register values around, rebox values, and ensure spilled, to match the
- // non-speculative path's requirements).
+ // We generate the speculative code path, followed by OSR exit code to return
+ // to the old JIT code if speculations fail.
#if ENABLE(DFG_JIT_BREAK_ON_EVERY_FUNCTION)
// Handy debug tool!
breakpoint();
#endif
- // First generate the speculative path.
Label speculativePathBegin = label();
SpeculativeJIT speculative(*this);
-#if !ENABLE(DFG_DEBUG_LOCAL_DISBALE_SPECULATIVE)
bool compiledSpeculative = speculative.compile();
-#else
- bool compiledSpeculative = false;
-#endif
+ ASSERT_UNUSED(compiledSpeculative, compiledSpeculative);
- // Next, generate the non-speculative path. We pass this a SpeculationCheckIndexIterator
- // to allow it to check which nodes in the graph may bail out, and may need to reenter the
- // non-speculative path.
- if (compiledSpeculative) {
#if ENABLE(DFG_OSR_ENTRY)
- m_codeBlock->setJITCodeMap(m_jitCodeMapEncoder.finish());
+ m_codeBlock->setJITCodeMap(m_jitCodeMapEncoder.finish());
#endif
-
-#if ENABLE(DFG_OSR_EXIT)
- linkOSRExits(speculative);
-#else
- SpeculationCheckIndexIterator checkIterator(speculative.speculationChecks());
- NonSpeculativeJIT nonSpeculative(*this);
- nonSpeculative.compile(checkIterator);
-
- // Link the bail-outs from the speculative path to the corresponding entry points into the non-speculative one.
- linkSpeculationChecks(speculative, nonSpeculative);
-#endif
- } else {
- // If compilation through the SpeculativeJIT failed, throw away the code we generated.
- m_calls.clear();
- m_propertyAccesses.clear();
- m_jsCalls.clear();
- m_methodGets.clear();
- rewindToLabel(speculativePathBegin);
-
-#if ENABLE(DFG_OSR_EXIT)
- SpeculationCheckIndexIterator checkIterator;
-#else
- SpeculationCheckVector noChecks;
- SpeculationCheckIndexIterator checkIterator(noChecks);
-#endif
- NonSpeculativeJIT nonSpeculative(*this);
- nonSpeculative.compile(checkIterator);
- }
+
+ linkOSRExits(speculative);
// Iterate over the m_calls vector, checking for exception checks,
// and linking them to here.