C++程序  |  260行  |  9.72 KB

/*
 * 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. 
 */

#ifndef DFGNonSpeculativeJIT_h
#define DFGNonSpeculativeJIT_h

#if ENABLE(DFG_JIT)

#include <dfg/DFGJITCodeGenerator.h>

namespace JSC { namespace DFG {

class SpeculationCheckIndexIterator;

// === EntryLocation ===
//
// This structure describes an entry point into the non-speculative
// code path. This is used in linking bail-outs from the speculative path.
struct EntryLocation {
    EntryLocation(MacroAssembler::Label, NonSpeculativeJIT*);

    // The node this entry point corresponds to, and the label
    // marking the start of code for the given node.
    MacroAssembler::Label m_entry;
    NodeIndex m_nodeIndex;

    // For every entry point we record a map recording for every
    // machine register which, if any, values it contains. For
    // GPR registers we must also record the format of the value.
    struct RegisterInfo {
        NodeIndex nodeIndex;
        DataFormat format;
    };
    RegisterInfo m_gprInfo[numberOfGPRs];
    NodeIndex m_fprInfo[numberOfFPRs];
};

// === NonSpeculativeJIT ===
//
// This class is used to generate code for the non-speculative path.
// Code generation will take advantage of static information available
// in the dataflow to perform safe optimizations - for example, avoiding
// boxing numeric values between arithmetic operations, but will not
// perform any unsafe optimizations that would render the code unable
// to produce the correct results for any possible input.
class NonSpeculativeJIT : public JITCodeGenerator {
    friend struct EntryLocation;
public:
    NonSpeculativeJIT(JITCompiler& jit)
        : JITCodeGenerator(jit, false)
    {
    }

    void compile(SpeculationCheckIndexIterator&);

    typedef SegmentedVector<EntryLocation, 16> EntryLocationVector;
    EntryLocationVector& entryLocations() { return m_entryLocations; }

private:
    void compile(SpeculationCheckIndexIterator&, Node&);
    void compile(SpeculationCheckIndexIterator&, BasicBlock&);

    bool isKnownInteger(NodeIndex);
    bool isKnownNumeric(NodeIndex);

    // These methods are used when generating 'unexpected'
    // calls out from JIT code to C++ helper routines -
    // they spill all live values to the appropriate
    // slots in the RegisterFile without changing any state
    // in the GenerationInfo.
    void silentSpillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
    {
        GenerationInfo& info = m_generationInfo[spillMe];
        ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);

        if (!info.needsSpill() || (info.gpr() == exclude))
            return;

        DataFormat registerFormat = info.registerFormat();
        JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());

        if (registerFormat == DataFormatInteger) {
            m_jit.orPtr(JITCompiler::tagTypeNumberRegister, reg);
            m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
        } else {
            ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
            m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
        }
    }
    void silentSpillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
    {
        GenerationInfo& info = m_generationInfo[spillMe];
        ASSERT(info.registerFormat() == DataFormatDouble);

        if (!info.needsSpill() || (info.fpr() == exclude))
            return;

        boxDouble(info.fpr(), canTrample);
        m_jit.storePtr(JITCompiler::gprToRegisterID(canTrample), JITCompiler::addressFor(spillMe));
    }

    void silentFillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
    {
        GenerationInfo& info = m_generationInfo[spillMe];
        if (info.gpr() == exclude)
            return;

        NodeIndex nodeIndex = info.nodeIndex();
        Node& node = m_jit.graph()[nodeIndex];
        ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
        DataFormat registerFormat = info.registerFormat();
        JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());

        if (registerFormat == DataFormatInteger) {
            if (node.isConstant()) {
                ASSERT(isInt32Constant(nodeIndex));
                m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), reg);
            } else
                m_jit.load32(JITCompiler::addressFor(spillMe), reg);
            return;
        }

        if (node.isConstant())
            m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
        else {
            ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
            m_jit.loadPtr(JITCompiler::addressFor(spillMe), reg);
        }
    }
    void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
    {
        GenerationInfo& info = m_generationInfo[spillMe];
        if (info.fpr() == exclude)
            return;

        NodeIndex nodeIndex = info.nodeIndex();
        Node& node = m_jit.graph()[nodeIndex];
        ASSERT(info.registerFormat() == DataFormatDouble);

        if (node.isConstant()) {
            JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
            m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
        } else {
            m_jit.loadPtr(JITCompiler::addressFor(spillMe), JITCompiler::gprToRegisterID(canTrample));
            unboxDouble(canTrample, info.fpr());
        }
    }

    void silentSpillAllRegisters(GPRReg exclude, GPRReg preserve = InvalidGPRReg)
    {
        GPRReg canTrample = (preserve == gpr0) ? gpr1 : gpr0;
        
        for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
            VirtualRegister name = m_gprs.name(gpr);
            if (name != InvalidVirtualRegister)
                silentSpillGPR(name, exclude);
        }
        for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
            VirtualRegister name = m_fprs.name(fpr);
            if (name != InvalidVirtualRegister)
                silentSpillFPR(name, canTrample);
        }
    }
    void silentSpillAllRegisters(FPRReg exclude, GPRReg preserve = InvalidGPRReg)
    {
        GPRReg canTrample = (preserve == gpr0) ? gpr1 : gpr0;
        
        for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
            VirtualRegister name = m_gprs.name(gpr);
            if (name != InvalidVirtualRegister)
                silentSpillGPR(name);
        }
        for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
            VirtualRegister name = m_fprs.name(fpr);
            if (name != InvalidVirtualRegister)
                silentSpillFPR(name, canTrample, exclude);
        }
    }
    void silentFillAllRegisters(GPRReg exclude)
    {
        GPRReg canTrample = (exclude == gpr0) ? gpr1 : gpr0;
        
        for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
            VirtualRegister name = m_fprs.name(fpr);
            if (name != InvalidVirtualRegister)
                silentFillFPR(name, canTrample);
        }
        for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
            VirtualRegister name = m_gprs.name(gpr);
            if (name != InvalidVirtualRegister)
                silentFillGPR(name, exclude);
        }
    }
    void silentFillAllRegisters(FPRReg exclude)
    {
        GPRReg canTrample = gpr0;
        
        for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
            VirtualRegister name = m_fprs.name(fpr);
            if (name != InvalidVirtualRegister) {
#ifndef NDEBUG
                ASSERT(fpr != exclude);
#else
                UNUSED_PARAM(exclude);
#endif
                silentFillFPR(name, canTrample, exclude);
            }
        }
        for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
            VirtualRegister name = m_gprs.name(gpr);
            if (name != InvalidVirtualRegister)
                silentFillGPR(name);
        }
    }

    // These methods are used to plant calls out to C++
    // helper routines to convert between types.
    void valueToNumber(JSValueOperand&, FPRReg result);
    void valueToInt32(JSValueOperand&, GPRReg result);
    void numberToInt32(FPRReg, GPRReg result);

    // Record an entry location into the non-speculative code path;
    // for every bail-out on the speculative path we record information
    // to be able to re-enter into the non-speculative one.
    void trackEntry(MacroAssembler::Label entry)
    {
        m_entryLocations.append(EntryLocation(entry, this));
    }

    EntryLocationVector m_entryLocations;
};

} } // namespace JSC::DFG

#endif
#endif