/*
 * Copyright (C) 2011 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 "DFGNonSpeculativeJIT.h"

#include "DFGSpeculativeJIT.h"

#if ENABLE(DFG_JIT)

namespace JSC { namespace DFG {

const double twoToThe32 = (double)0x100000000ull;

EntryLocation::EntryLocation(MacroAssembler::Label entry, NonSpeculativeJIT* jit)
    : m_entry(entry)
    , m_nodeIndex(jit->m_compileIndex)
{
    for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
        VirtualRegister virtualRegister = jit->m_gprs.name(gpr);
        if (virtualRegister != InvalidVirtualRegister) {
            GenerationInfo& info =  jit->m_generationInfo[virtualRegister];
            m_gprInfo[gpr].nodeIndex = info.nodeIndex();
            m_gprInfo[gpr].format = info.registerFormat();
        } else
            m_gprInfo[gpr].nodeIndex = NoNode;
    }
    for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
        VirtualRegister virtualRegister = jit->m_fprs.name(fpr);
        if (virtualRegister != InvalidVirtualRegister) {
            GenerationInfo& info =  jit->m_generationInfo[virtualRegister];
            ASSERT(info.registerFormat() == DataFormatDouble);
            m_fprInfo[fpr] = info.nodeIndex();
        } else
            m_fprInfo[fpr] = NoNode;
    }
}

void NonSpeculativeJIT::valueToNumber(JSValueOperand& operand, FPRReg fpr)
{
    GPRReg jsValueGpr = operand.gpr();
    GPRReg tempGpr = allocate(); // FIXME: can we skip this allocation on the last use of the virtual register?

    JITCompiler::RegisterID jsValueReg = JITCompiler::gprToRegisterID(jsValueGpr);
    JITCompiler::FPRegisterID fpReg = JITCompiler::fprToRegisterID(fpr);
    JITCompiler::RegisterID tempReg = JITCompiler::gprToRegisterID(tempGpr);

    JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueReg, JITCompiler::tagTypeNumberRegister);
    JITCompiler::Jump nonNumeric = m_jit.branchTestPtr(MacroAssembler::Zero, jsValueReg, JITCompiler::tagTypeNumberRegister);

    // First, if we get here we have a double encoded as a JSValue
    m_jit.move(jsValueReg, tempReg);
    m_jit.addPtr(JITCompiler::tagTypeNumberRegister, tempReg);
    m_jit.movePtrToDouble(tempReg, fpReg);
    JITCompiler::Jump hasUnboxedDouble = m_jit.jump();

    // Next handle cells (& other JS immediates)
    nonNumeric.link(&m_jit);
    silentSpillAllRegisters(fpr, jsValueGpr);
    m_jit.move(jsValueReg, JITCompiler::argumentRegister1);
    m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
    appendCallWithExceptionCheck(dfgConvertJSValueToNumber);
    m_jit.moveDouble(JITCompiler::fpReturnValueRegister, fpReg);
    silentFillAllRegisters(fpr);
    JITCompiler::Jump hasCalledToNumber = m_jit.jump();
    
    // Finally, handle integers.
    isInteger.link(&m_jit);
    m_jit.convertInt32ToDouble(jsValueReg, fpReg);
    hasUnboxedDouble.link(&m_jit);
    hasCalledToNumber.link(&m_jit);

    m_gprs.unlock(tempGpr);
}

void NonSpeculativeJIT::valueToInt32(JSValueOperand& operand, GPRReg result)
{
    GPRReg jsValueGpr = operand.gpr();

    JITCompiler::RegisterID jsValueReg = JITCompiler::gprToRegisterID(jsValueGpr);
    JITCompiler::RegisterID resultReg = JITCompiler::gprToRegisterID(result);

    JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueReg, JITCompiler::tagTypeNumberRegister);

    // First handle non-integers
    silentSpillAllRegisters(result, jsValueGpr);
    m_jit.move(jsValueReg, JITCompiler::argumentRegister1);
    m_jit.move(JITCompiler::callFrameRegister, JITCompiler::argumentRegister0);
    appendCallWithExceptionCheck(dfgConvertJSValueToInt32);
    m_jit.zeroExtend32ToPtr(JITCompiler::returnValueRegister, resultReg);
    silentFillAllRegisters(result);
    JITCompiler::Jump hasCalledToInt32 = m_jit.jump();
    
    // Then handle integers.
    isInteger.link(&m_jit);
    m_jit.zeroExtend32ToPtr(jsValueReg, resultReg);
    hasCalledToInt32.link(&m_jit);
}

void NonSpeculativeJIT::numberToInt32(FPRReg fpr, GPRReg gpr)
{
    JITCompiler::FPRegisterID fpReg = JITCompiler::fprToRegisterID(fpr);
    JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);

    JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpReg, reg, JITCompiler::BranchIfTruncateSuccessful);

    silentSpillAllRegisters(gpr);

    m_jit.moveDouble(fpReg, JITCompiler::fpArgumentRegister0);
    appendCallWithExceptionCheck(toInt32);
    m_jit.zeroExtend32ToPtr(JITCompiler::returnValueRegister, reg);

    silentFillAllRegisters(gpr);

    truncatedToInteger.link(&m_jit);
}

bool NonSpeculativeJIT::isKnownInteger(NodeIndex nodeIndex)
{
    GenerationInfo& info = m_generationInfo[m_jit.graph()[nodeIndex].virtualRegister];

    DataFormat registerFormat = info.registerFormat();
    if (registerFormat != DataFormatNone)
        return (registerFormat | DataFormatJS) == DataFormatJSInteger;

    DataFormat spillFormat = info.spillFormat();
    if (spillFormat != DataFormatNone)
        return (spillFormat | DataFormatJS) == DataFormatJSInteger;

    ASSERT(isConstant(nodeIndex));
    return isInt32Constant(nodeIndex);
}

bool NonSpeculativeJIT::isKnownNumeric(NodeIndex nodeIndex)
{
    GenerationInfo& info = m_generationInfo[m_jit.graph()[nodeIndex].virtualRegister];

    DataFormat registerFormat = info.registerFormat();
    if (registerFormat != DataFormatNone)
        return (registerFormat | DataFormatJS) == DataFormatJSInteger
            || (registerFormat | DataFormatJS) == DataFormatJSDouble;

    DataFormat spillFormat = info.spillFormat();
    if (spillFormat != DataFormatNone)
        return (spillFormat | DataFormatJS) == DataFormatJSInteger
            || (spillFormat | DataFormatJS) == DataFormatJSDouble;

    ASSERT(isConstant(nodeIndex));
    return isInt32Constant(nodeIndex) || isDoubleConstant(nodeIndex);
}

void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, Node& node)
{
    // ...
    if (checkIterator.hasCheckAtIndex(m_compileIndex))
        trackEntry(m_jit.label());

    checkConsistency();
    NodeType op = node.op;

    switch (op) {
    case ConvertThis: {
        JSValueOperand thisValue(this, node.child1);
        GPRReg thisGPR = thisValue.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(operationConvertThis, result.gpr(), thisGPR);
        cellResult(result.gpr(), m_compileIndex);
        break;
    }

    case Int32Constant:
    case DoubleConstant:
    case JSConstant:
        initConstantInfo(m_compileIndex);
        break;

    case GetLocal: {
        GPRTemporary result(this);
        m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.registerID());
        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }

    case SetLocal: {
        JSValueOperand value(this, node.child1);
        m_jit.storePtr(value.registerID(), JITCompiler::addressFor(node.local()));
        noResult(m_compileIndex);
        break;
    }

    case BitAnd:
    case BitOr:
    case BitXor:
        if (isInt32Constant(node.child1)) {
            IntegerOperand op2(this, node.child2);
            GPRTemporary result(this, op2);

            bitOp(op, valueOfInt32Constant(node.child1), op2.registerID(), result.registerID());

            integerResult(result.gpr(), m_compileIndex);
        } else if (isInt32Constant(node.child2)) {
            IntegerOperand op1(this, node.child1);
            GPRTemporary result(this, op1);

            bitOp(op, valueOfInt32Constant(node.child2), op1.registerID(), result.registerID());

            integerResult(result.gpr(), m_compileIndex);
        } else {
            IntegerOperand op1(this, node.child1);
            IntegerOperand op2(this, node.child2);
            GPRTemporary result(this, op1, op2);

            MacroAssembler::RegisterID reg1 = op1.registerID();
            MacroAssembler::RegisterID reg2 = op2.registerID();
            bitOp(op, reg1, reg2, result.registerID());

            integerResult(result.gpr(), m_compileIndex);
        }
        break;

    case BitRShift:
    case BitLShift:
    case BitURShift:
        if (isInt32Constant(node.child2)) {
            IntegerOperand op1(this, node.child1);
            GPRTemporary result(this, op1);

            int shiftAmount = valueOfInt32Constant(node.child2) & 0x1f;
            // Shifts by zero should have been optimized out of the graph!
            ASSERT(shiftAmount);
            shiftOp(op, op1.registerID(), shiftAmount, result.registerID());

            integerResult(result.gpr(), m_compileIndex);
        } else {
            // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
            IntegerOperand op1(this, node.child1);
            IntegerOperand op2(this, node.child2);
            GPRTemporary result(this, op1);

            MacroAssembler::RegisterID reg1 = op1.registerID();
            MacroAssembler::RegisterID reg2 = op2.registerID();
            shiftOp(op, reg1, reg2, result.registerID());

            integerResult(result.gpr(), m_compileIndex);
        }
        break;

    case UInt32ToNumber: {
        IntegerOperand op1(this, node.child1);
        FPRTemporary result(this);
        m_jit.convertInt32ToDouble(op1.registerID(), result.registerID());

        MacroAssembler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, op1.registerID(), TrustedImm32(0));
        m_jit.addDouble(JITCompiler::AbsoluteAddress(&twoToThe32), result.registerID());
        positive.link(&m_jit);

        doubleResult(result.fpr(), m_compileIndex);
        break;
    }

    case Int32ToNumber: {
        IntegerOperand op1(this, node.child1);
        FPRTemporary result(this);
        m_jit.convertInt32ToDouble(op1.registerID(), result.registerID());
        doubleResult(result.fpr(), m_compileIndex);
        break;
    }

    case NumberToInt32:
    case ValueToInt32: {
        ASSERT(!isInt32Constant(node.child1));

        if (isKnownInteger(node.child1)) {
            IntegerOperand op1(this, node.child1);
            GPRTemporary result(this, op1);
            m_jit.move(op1.registerID(), result.registerID());
            integerResult(result.gpr(), m_compileIndex);
            break;
        }

        if (isKnownNumeric(node.child1)) {
            DoubleOperand op1(this, node.child1);
            GPRTemporary result(this);
            numberToInt32(op1.fpr(), result.gpr());
            integerResult(result.gpr(), m_compileIndex);
            break;
        }

        // We should have handled this via isKnownInteger, or isKnownNumeric!
        ASSERT(op != NumberToInt32);

        JSValueOperand op1(this, node.child1);
        GPRTemporary result(this, op1);
        valueToInt32(op1, result.gpr());
        integerResult(result.gpr(), m_compileIndex);
        break;
    }

    case ValueToNumber: {
        ASSERT(!isInt32Constant(node.child1));
        ASSERT(!isDoubleConstant(node.child1));

        if (isKnownInteger(node.child1)) {
            IntegerOperand op1(this, node.child1);
            FPRTemporary result(this);
            m_jit.convertInt32ToDouble(op1.registerID(), result.registerID());
            doubleResult(result.fpr(), m_compileIndex);
            break;
        }

        if (isKnownNumeric(node.child1)) {
            DoubleOperand op1(this, node.child1);
            FPRTemporary result(this, op1);
            m_jit.moveDouble(op1.registerID(), result.registerID());
            doubleResult(result.fpr(), m_compileIndex);
            break;
        }

        JSValueOperand op1(this, node.child1);
        FPRTemporary result(this);
        valueToNumber(op1, result.fpr());
        doubleResult(result.fpr(), m_compileIndex);
        break;
    }

    case ValueAdd: {
        JSValueOperand arg1(this, node.child1);
        JSValueOperand arg2(this, node.child2);
        GPRReg arg1GPR = arg1.gpr();
        GPRReg arg2GPR = arg2.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(operationValueAdd, result.gpr(), arg1GPR, arg2GPR);

        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }
        
    case ArithAdd: {
        DoubleOperand op1(this, node.child1);
        DoubleOperand op2(this, node.child2);
        FPRTemporary result(this, op1, op2);

        MacroAssembler::FPRegisterID reg1 = op1.registerID();
        MacroAssembler::FPRegisterID reg2 = op2.registerID();
        m_jit.addDouble(reg1, reg2, result.registerID());

        doubleResult(result.fpr(), m_compileIndex);
        break;
    }

    case ArithSub: {
        DoubleOperand op1(this, node.child1);
        DoubleOperand op2(this, node.child2);
        FPRTemporary result(this, op1);

        MacroAssembler::FPRegisterID reg1 = op1.registerID();
        MacroAssembler::FPRegisterID reg2 = op2.registerID();
        m_jit.subDouble(reg1, reg2, result.registerID());

        doubleResult(result.fpr(), m_compileIndex);
        break;
    }

    case ArithMul: {
        DoubleOperand op1(this, node.child1);
        DoubleOperand op2(this, node.child2);
        FPRTemporary result(this, op1, op2);

        MacroAssembler::FPRegisterID reg1 = op1.registerID();
        MacroAssembler::FPRegisterID reg2 = op2.registerID();
        m_jit.mulDouble(reg1, reg2, result.registerID());

        doubleResult(result.fpr(), m_compileIndex);
        break;
    }

    case ArithDiv: {
        DoubleOperand op1(this, node.child1);
        DoubleOperand op2(this, node.child2);
        FPRTemporary result(this, op1);

        MacroAssembler::FPRegisterID reg1 = op1.registerID();
        MacroAssembler::FPRegisterID reg2 = op2.registerID();
        m_jit.divDouble(reg1, reg2, result.registerID());

        doubleResult(result.fpr(), m_compileIndex);
        break;
    }

    case ArithMod: {
        DoubleOperand arg1(this, node.child1);
        DoubleOperand arg2(this, node.child2);
        FPRReg arg1FPR = arg1.fpr();
        FPRReg arg2FPR = arg2.fpr();
        flushRegisters();

        FPRResult result(this);
        callOperation(fmod, result.fpr(), arg1FPR, arg2FPR);

        doubleResult(result.fpr(), m_compileIndex);
        break;
    }

    case LogicalNot: {
        JSValueOperand arg1(this, node.child1);
        GPRReg arg1GPR = arg1.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(dfgConvertJSValueToBoolean, result.gpr(), arg1GPR);

        // If we add a DataFormatBool, we should use it here.
        m_jit.xor32(TrustedImm32(ValueTrue), result.registerID());
        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }

    case CompareLess: {
        JSValueOperand arg1(this, node.child1);
        JSValueOperand arg2(this, node.child2);
        GPRReg arg1GPR = arg1.gpr();
        GPRReg arg2GPR = arg2.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(operationCompareLess, result.gpr(), arg1GPR, arg2GPR);
        m_jit.or32(TrustedImm32(ValueFalse), result.registerID());

        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }

    case CompareLessEq: {
        JSValueOperand arg1(this, node.child1);
        JSValueOperand arg2(this, node.child2);
        GPRReg arg1GPR = arg1.gpr();
        GPRReg arg2GPR = arg2.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(operationCompareLessEq, result.gpr(), arg1GPR, arg2GPR);
        m_jit.or32(TrustedImm32(ValueFalse), result.registerID());

        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }

    case CompareEq: {
        JSValueOperand arg1(this, node.child1);
        JSValueOperand arg2(this, node.child2);
        GPRReg arg1GPR = arg1.gpr();
        GPRReg arg2GPR = arg2.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(operationCompareEq, result.gpr(), arg1GPR, arg2GPR);
        m_jit.or32(TrustedImm32(ValueFalse), result.registerID());

        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }

    case CompareStrictEq: {
        JSValueOperand arg1(this, node.child1);
        JSValueOperand arg2(this, node.child2);
        GPRReg arg1GPR = arg1.gpr();
        GPRReg arg2GPR = arg2.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(operationCompareStrictEq, result.gpr(), arg1GPR, arg2GPR);
        m_jit.or32(TrustedImm32(ValueFalse), result.registerID());

        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }

    case GetByVal: {
        JSValueOperand arg1(this, node.child1);
        JSValueOperand arg2(this, node.child2);
        GPRReg arg1GPR = arg1.gpr();
        GPRReg arg2GPR = arg2.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(operationGetByVal, result.gpr(), arg1GPR, arg2GPR);

        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }

    case PutByVal:
    case PutByValAlias: {
        JSValueOperand arg1(this, node.child1);
        JSValueOperand arg2(this, node.child2);
        JSValueOperand arg3(this, node.child3);
        GPRReg arg1GPR = arg1.gpr();
        GPRReg arg2GPR = arg2.gpr();
        GPRReg arg3GPR = arg3.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValStrict : operationPutByValNonStrict, arg1GPR, arg2GPR, arg3GPR);

        noResult(m_compileIndex);
        break;
    }

    case GetById: {
        JSValueOperand base(this, node.child1);
        GPRReg baseGPR = base.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(operationGetById, result.gpr(), baseGPR, identifier(node.identifierNumber()));
        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }

    case PutById: {
        JSValueOperand base(this, node.child1);
        JSValueOperand value(this, node.child2);
        GPRReg valueGPR = value.gpr();
        GPRReg baseGPR = base.gpr();
        flushRegisters();

        callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdStrict : operationPutByIdNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
        noResult(m_compileIndex);
        break;
    }

    case PutByIdDirect: {
        JSValueOperand base(this, node.child1);
        JSValueOperand value(this, node.child2);
        GPRReg valueGPR = value.gpr();
        GPRReg baseGPR = base.gpr();
        flushRegisters();

        callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdDirectStrict : operationPutByIdDirectNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
        noResult(m_compileIndex);
        break;
    }

    case GetGlobalVar: {
        GPRTemporary result(this);

        JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
        m_jit.loadPtr(globalObject->addressOfRegisters(), result.registerID());
        m_jit.loadPtr(JITCompiler::addressForGlobalVar(result.registerID(), node.varNumber()), result.registerID());

        jsValueResult(result.gpr(), m_compileIndex);
        break;
    }

    case PutGlobalVar: {
        JSValueOperand value(this, node.child1);
        GPRTemporary temp(this);

        JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
        m_jit.loadPtr(globalObject->addressOfRegisters(), temp.registerID());
        m_jit.storePtr(value.registerID(), JITCompiler::addressForGlobalVar(temp.registerID(), node.varNumber()));

        noResult(m_compileIndex);
        break;
    }

    case DFG::Jump: {
        BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
        if (taken != (m_block + 1))
            addBranch(m_jit.jump(), taken);
        noResult(m_compileIndex);
        break;
    }

    case Branch: {
        JSValueOperand value(this, node.child1);
        GPRReg valueGPR = value.gpr();
        flushRegisters();

        GPRResult result(this);
        callOperation(dfgConvertJSValueToBoolean, result.gpr(), valueGPR);

        BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
        BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(node.notTakenBytecodeOffset());

        addBranch(m_jit.branchTest8(MacroAssembler::NonZero, result.registerID()), taken);
        if (notTaken != (m_block + 1))
            addBranch(m_jit.jump(), notTaken);

        noResult(m_compileIndex);
        break;
    }

    case Return: {
        ASSERT(JITCompiler::callFrameRegister != JITCompiler::regT1);
        ASSERT(JITCompiler::regT1 != JITCompiler::returnValueRegister);
        ASSERT(JITCompiler::returnValueRegister != JITCompiler::callFrameRegister);

#if DFG_SUCCESS_STATS
        static SamplingCounter counter("NonSpeculativeJIT");
        m_jit.emitCount(counter);
#endif

        // Return the result in returnValueRegister.
        JSValueOperand op1(this, node.child1);
        m_jit.move(op1.registerID(), JITCompiler::returnValueRegister);

        // Grab the return address.
        m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, JITCompiler::regT1);
        // Restore our caller's "r".
        m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, JITCompiler::callFrameRegister);
        // Return.
        m_jit.restoreReturnAddressBeforeReturn(JITCompiler::regT1);
        m_jit.ret();

        noResult(m_compileIndex);
        break;
    }
    }

    if (node.mustGenerate())
        use(m_compileIndex);

    checkConsistency();
}

void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator, BasicBlock& block)
{
    ASSERT(m_compileIndex == block.begin);
    m_blockHeads[m_block] = m_jit.label();

#if DFG_JIT_BREAK_ON_EVERY_BLOCK
    m_jit.breakpoint();
#endif

    for (; m_compileIndex < block.end; ++m_compileIndex) {
        Node& node = m_jit.graph()[m_compileIndex];
        if (!node.refCount)
            continue;

#if DFG_DEBUG_VERBOSE
        fprintf(stderr, "NonSpeculativeJIT generating Node @%d at code offset 0x%x\n", (int)m_compileIndex, m_jit.debugOffset());
#endif
#if DFG_JIT_BREAK_ON_EVERY_NODE
    m_jit.breakpoint();
#endif

        compile(checkIterator, node);
    }
}

void NonSpeculativeJIT::compile(SpeculationCheckIndexIterator& checkIterator)
{
    ASSERT(!m_compileIndex);
    Vector<BasicBlock> blocks = m_jit.graph().m_blocks;
    for (m_block = 0; m_block < blocks.size(); ++m_block)
        compile(checkIterator, blocks[m_block]);
    linkBranches();
}

} } // namespace JSC::DFG

#endif