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