Home | History | Annotate | Download | only in dfg
      1 /*
      2  * Copyright (C) 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #ifndef DFGSpeculativeJIT_h
     27 #define DFGSpeculativeJIT_h
     28 
     29 #if ENABLE(DFG_JIT)
     30 
     31 #include <dfg/DFGJITCodeGenerator.h>
     32 
     33 namespace JSC { namespace DFG {
     34 
     35 class SpeculativeJIT;
     36 
     37 // This enum describes the types of additional recovery that
     38 // may need be performed should a speculation check fail.
     39 enum SpeculationRecoveryType {
     40     SpeculativeAdd
     41 };
     42 
     43 // === SpeculationRecovery ===
     44 //
     45 // This class provides additional information that may be associated with a
     46 // speculation check - for example
     47 class SpeculationRecovery {
     48 public:
     49     SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, GPRReg src)
     50         : m_type(type)
     51         , m_dest(dest)
     52         , m_src(src)
     53     {
     54     }
     55 
     56     SpeculationRecoveryType type() { return m_type; }
     57     GPRReg dest() { return m_dest; }
     58     GPRReg src() { return m_src; }
     59 
     60 private:
     61     // Indicates the type of additional recovery to be performed.
     62     SpeculationRecoveryType m_type;
     63     // different recovery types may required different additional information here.
     64     GPRReg m_dest;
     65     GPRReg m_src;
     66 };
     67 
     68 // === SpeculationCheck ===
     69 //
     70 // This structure records a bail-out from the speculative path,
     71 // which will need to be linked in to the non-speculative one.
     72 struct SpeculationCheck {
     73     SpeculationCheck(MacroAssembler::Jump, SpeculativeJIT*, unsigned recoveryIndex = 0);
     74 
     75     // The location of the jump out from the speculative path,
     76     // and the node we were generating code for.
     77     MacroAssembler::Jump m_check;
     78     NodeIndex m_nodeIndex;
     79     // Used to record any additional recovery to be performed; this
     80     // value is an index into the SpeculativeJIT's m_speculationRecoveryList
     81     // array, offset by 1. (m_recoveryIndex == 0) means no recovery.
     82     unsigned m_recoveryIndex;
     83 
     84     struct RegisterInfo {
     85         NodeIndex nodeIndex;
     86         DataFormat format;
     87     };
     88     RegisterInfo m_gprInfo[numberOfGPRs];
     89     NodeIndex m_fprInfo[numberOfFPRs];
     90 };
     91 typedef SegmentedVector<SpeculationCheck, 16> SpeculationCheckVector;
     92 
     93 
     94 // === SpeculativeJIT ===
     95 //
     96 // The SpeculativeJIT is used to generate a fast, but potentially
     97 // incomplete code path for the dataflow. When code generating
     98 // we may make assumptions about operand types, dynamically check,
     99 // and bail-out to an alternate code path if these checks fail.
    100 // Importantly, the speculative code path cannot be reentered once
    101 // a speculative check has failed. This allows the SpeculativeJIT
    102 // to propagate type information (including information that has
    103 // only speculatively been asserted) through the dataflow.
    104 class SpeculativeJIT : public JITCodeGenerator {
    105     friend struct SpeculationCheck;
    106 public:
    107     SpeculativeJIT(JITCompiler& jit)
    108         : JITCodeGenerator(jit, true)
    109         , m_didTerminate(false)
    110     {
    111     }
    112 
    113     bool compile();
    114 
    115     // Retrieve the list of bail-outs from the speculative path,
    116     // and additional recovery information.
    117     SpeculationCheckVector& speculationChecks()
    118     {
    119         return m_speculationChecks;
    120     }
    121     SpeculationRecovery* speculationRecovery(size_t index)
    122     {
    123         // SpeculationCheck::m_recoveryIndex is offset by 1,
    124         // 0 means no recovery.
    125         return index ? &m_speculationRecoveryList[index - 1] : 0;
    126     }
    127 
    128     // Called by the speculative operand types, below, to fill operand to
    129     // machine registers, implicitly generating speculation checks as needed.
    130     GPRReg fillSpeculateInt(NodeIndex, DataFormat& returnFormat);
    131     GPRReg fillSpeculateIntStrict(NodeIndex);
    132     GPRReg fillSpeculateCell(NodeIndex);
    133 
    134 private:
    135     bool compile(Node&);
    136     bool compile(BasicBlock&);
    137 
    138     bool isDoubleConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
    139     {
    140         if (!m_jit.isDoubleConstant(nodeIndex))
    141             return false;
    142         double value = m_jit.valueOfDoubleConstant(nodeIndex);
    143 
    144         int32_t asInt32 = static_cast<int32_t>(value);
    145         if (value != asInt32)
    146             return false;
    147         if (!asInt32 && signbit(value))
    148             return false;
    149 
    150         out = asInt32;
    151         return true;
    152     }
    153 
    154     // Add a speculation check without additional recovery.
    155     void speculationCheck(MacroAssembler::Jump jumpToFail)
    156     {
    157         m_speculationChecks.append(SpeculationCheck(jumpToFail, this));
    158     }
    159     // Add a speculation check with additional recovery.
    160     void speculationCheck(MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
    161     {
    162         m_speculationRecoveryList.append(recovery);
    163         m_speculationChecks.append(SpeculationCheck(jumpToFail, this, m_speculationRecoveryList.size()));
    164     }
    165 
    166     // Called when we statically determine that a speculation will fail.
    167     void terminateSpeculativeExecution()
    168     {
    169         // FIXME: in cases where we can statically determine we're going to bail out from the speculative
    170         // JIT we should probably rewind code generation and only produce the non-speculative path.
    171         m_didTerminate = true;
    172         speculationCheck(m_jit.jump());
    173     }
    174 
    175     template<bool strict>
    176     GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat);
    177 
    178     // It is possible, during speculative generation, to reach a situation in which we
    179     // can statically determine a speculation will fail (for example, when two nodes
    180     // will make conflicting speculations about the same operand). In such cases this
    181     // flag is set, indicating no further code generation should take place.
    182     bool m_didTerminate;
    183     // This vector tracks bail-outs from the speculative path to the non-speculative one.
    184     SpeculationCheckVector m_speculationChecks;
    185     // Some bail-outs need to record additional information recording specific recovery
    186     // to be performed (for example, on detected overflow from an add, we may need to
    187     // reverse the addition if an operand is being overwritten).
    188     Vector<SpeculationRecovery, 16> m_speculationRecoveryList;
    189 };
    190 
    191 
    192 // === Speculative Operand types ===
    193 //
    194 // SpeculateIntegerOperand, SpeculateStrictInt32Operand and SpeculateCellOperand.
    195 //
    196 // These are used to lock the operands to a node into machine registers within the
    197 // SpeculativeJIT. The classes operate like those provided by the JITCodeGenerator,
    198 // however these will perform a speculative check for a more restrictive type than
    199 // we can statically determine the operand to have. If the operand does not have
    200 // the requested type, a bail-out to the non-speculative path will be taken.
    201 
    202 class SpeculateIntegerOperand {
    203 public:
    204     explicit SpeculateIntegerOperand(SpeculativeJIT* jit, NodeIndex index)
    205         : m_jit(jit)
    206         , m_index(index)
    207         , m_gprOrInvalid(InvalidGPRReg)
    208 #ifndef NDEBUG
    209         , m_format(DataFormatNone)
    210 #endif
    211     {
    212         ASSERT(m_jit);
    213         if (jit->isFilled(index))
    214             gpr();
    215     }
    216 
    217     ~SpeculateIntegerOperand()
    218     {
    219         ASSERT(m_gprOrInvalid != InvalidGPRReg);
    220         m_jit->unlock(m_gprOrInvalid);
    221     }
    222 
    223     NodeIndex index() const
    224     {
    225         return m_index;
    226     }
    227 
    228     GPRReg gpr()
    229     {
    230         if (m_gprOrInvalid == InvalidGPRReg)
    231             m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format);
    232         return m_gprOrInvalid;
    233     }
    234 
    235     DataFormat format()
    236     {
    237         gpr(); // m_format is set when m_gpr is locked.
    238         ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
    239         return m_format;
    240     }
    241 
    242     MacroAssembler::RegisterID registerID()
    243     {
    244         return JITCompiler::gprToRegisterID(gpr());
    245     }
    246 
    247 private:
    248     SpeculativeJIT* m_jit;
    249     NodeIndex m_index;
    250     GPRReg m_gprOrInvalid;
    251     DataFormat m_format;
    252 };
    253 
    254 class SpeculateStrictInt32Operand {
    255 public:
    256     explicit SpeculateStrictInt32Operand(SpeculativeJIT* jit, NodeIndex index)
    257         : m_jit(jit)
    258         , m_index(index)
    259         , m_gprOrInvalid(InvalidGPRReg)
    260     {
    261         ASSERT(m_jit);
    262         if (jit->isFilled(index))
    263             gpr();
    264     }
    265 
    266     ~SpeculateStrictInt32Operand()
    267     {
    268         ASSERT(m_gprOrInvalid != InvalidGPRReg);
    269         m_jit->unlock(m_gprOrInvalid);
    270     }
    271 
    272     NodeIndex index() const
    273     {
    274         return m_index;
    275     }
    276 
    277     GPRReg gpr()
    278     {
    279         if (m_gprOrInvalid == InvalidGPRReg)
    280             m_gprOrInvalid = m_jit->fillSpeculateIntStrict(index());
    281         return m_gprOrInvalid;
    282     }
    283 
    284     MacroAssembler::RegisterID registerID()
    285     {
    286         return JITCompiler::gprToRegisterID(gpr());
    287     }
    288 
    289 private:
    290     SpeculativeJIT* m_jit;
    291     NodeIndex m_index;
    292     GPRReg m_gprOrInvalid;
    293 };
    294 
    295 class SpeculateCellOperand {
    296 public:
    297     explicit SpeculateCellOperand(SpeculativeJIT* jit, NodeIndex index)
    298         : m_jit(jit)
    299         , m_index(index)
    300         , m_gprOrInvalid(InvalidGPRReg)
    301     {
    302         ASSERT(m_jit);
    303         if (jit->isFilled(index))
    304             gpr();
    305     }
    306 
    307     ~SpeculateCellOperand()
    308     {
    309         ASSERT(m_gprOrInvalid != InvalidGPRReg);
    310         m_jit->unlock(m_gprOrInvalid);
    311     }
    312 
    313     NodeIndex index() const
    314     {
    315         return m_index;
    316     }
    317 
    318     GPRReg gpr()
    319     {
    320         if (m_gprOrInvalid == InvalidGPRReg)
    321             m_gprOrInvalid = m_jit->fillSpeculateCell(index());
    322         return m_gprOrInvalid;
    323     }
    324 
    325     MacroAssembler::RegisterID registerID()
    326     {
    327         return JITCompiler::gprToRegisterID(gpr());
    328     }
    329 
    330 private:
    331     SpeculativeJIT* m_jit;
    332     NodeIndex m_index;
    333     GPRReg m_gprOrInvalid;
    334 };
    335 
    336 
    337 // === SpeculationCheckIndexIterator ===
    338 //
    339 // This class is used by the non-speculative JIT to check which
    340 // nodes require entry points from the speculative path.
    341 class SpeculationCheckIndexIterator {
    342 public:
    343     SpeculationCheckIndexIterator(SpeculationCheckVector& speculationChecks)
    344         : m_speculationChecks(speculationChecks)
    345         , m_iter(m_speculationChecks.begin())
    346         , m_end(m_speculationChecks.end())
    347     {
    348     }
    349 
    350     bool hasCheckAtIndex(NodeIndex nodeIndex)
    351     {
    352         while (m_iter != m_end) {
    353             NodeIndex current = m_iter->m_nodeIndex;
    354             if (current >= nodeIndex)
    355                 return current == nodeIndex;
    356             ++m_iter;
    357         }
    358         return false;
    359     }
    360 
    361 private:
    362     SpeculationCheckVector& m_speculationChecks;
    363     SpeculationCheckVector::Iterator m_iter;
    364     SpeculationCheckVector::Iterator m_end;
    365 };
    366 
    367 
    368 } } // namespace JSC::DFG
    369 
    370 #endif
    371 #endif
    372 
    373