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 DFGNonSpeculativeJIT_h
     27 #define DFGNonSpeculativeJIT_h
     28 
     29 #if ENABLE(DFG_JIT)
     30 
     31 #include <dfg/DFGJITCodeGenerator.h>
     32 
     33 namespace JSC { namespace DFG {
     34 
     35 class SpeculationCheckIndexIterator;
     36 
     37 // === EntryLocation ===
     38 //
     39 // This structure describes an entry point into the non-speculative
     40 // code path. This is used in linking bail-outs from the speculative path.
     41 struct EntryLocation {
     42     EntryLocation(MacroAssembler::Label, NonSpeculativeJIT*);
     43 
     44     // The node this entry point corresponds to, and the label
     45     // marking the start of code for the given node.
     46     MacroAssembler::Label m_entry;
     47     NodeIndex m_nodeIndex;
     48 
     49     // For every entry point we record a map recording for every
     50     // machine register which, if any, values it contains. For
     51     // GPR registers we must also record the format of the value.
     52     struct RegisterInfo {
     53         NodeIndex nodeIndex;
     54         DataFormat format;
     55     };
     56     RegisterInfo m_gprInfo[numberOfGPRs];
     57     NodeIndex m_fprInfo[numberOfFPRs];
     58 };
     59 
     60 // === NonSpeculativeJIT ===
     61 //
     62 // This class is used to generate code for the non-speculative path.
     63 // Code generation will take advantage of static information available
     64 // in the dataflow to perform safe optimizations - for example, avoiding
     65 // boxing numeric values between arithmetic operations, but will not
     66 // perform any unsafe optimizations that would render the code unable
     67 // to produce the correct results for any possible input.
     68 class NonSpeculativeJIT : public JITCodeGenerator {
     69     friend struct EntryLocation;
     70 public:
     71     NonSpeculativeJIT(JITCompiler& jit)
     72         : JITCodeGenerator(jit, false)
     73     {
     74     }
     75 
     76     void compile(SpeculationCheckIndexIterator&);
     77 
     78     typedef SegmentedVector<EntryLocation, 16> EntryLocationVector;
     79     EntryLocationVector& entryLocations() { return m_entryLocations; }
     80 
     81 private:
     82     void compile(SpeculationCheckIndexIterator&, Node&);
     83     void compile(SpeculationCheckIndexIterator&, BasicBlock&);
     84 
     85     bool isKnownInteger(NodeIndex);
     86     bool isKnownNumeric(NodeIndex);
     87 
     88     // These methods are used when generating 'unexpected'
     89     // calls out from JIT code to C++ helper routines -
     90     // they spill all live values to the appropriate
     91     // slots in the RegisterFile without changing any state
     92     // in the GenerationInfo.
     93     void silentSpillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
     94     {
     95         GenerationInfo& info = m_generationInfo[spillMe];
     96         ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
     97 
     98         if (!info.needsSpill() || (info.gpr() == exclude))
     99             return;
    100 
    101         DataFormat registerFormat = info.registerFormat();
    102         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
    103 
    104         if (registerFormat == DataFormatInteger) {
    105             m_jit.orPtr(JITCompiler::tagTypeNumberRegister, reg);
    106             m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
    107         } else {
    108             ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
    109             m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
    110         }
    111     }
    112     void silentSpillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
    113     {
    114         GenerationInfo& info = m_generationInfo[spillMe];
    115         ASSERT(info.registerFormat() == DataFormatDouble);
    116 
    117         if (!info.needsSpill() || (info.fpr() == exclude))
    118             return;
    119 
    120         boxDouble(info.fpr(), canTrample);
    121         m_jit.storePtr(JITCompiler::gprToRegisterID(canTrample), JITCompiler::addressFor(spillMe));
    122     }
    123 
    124     void silentFillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
    125     {
    126         GenerationInfo& info = m_generationInfo[spillMe];
    127         if (info.gpr() == exclude)
    128             return;
    129 
    130         NodeIndex nodeIndex = info.nodeIndex();
    131         Node& node = m_jit.graph()[nodeIndex];
    132         ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
    133         DataFormat registerFormat = info.registerFormat();
    134         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
    135 
    136         if (registerFormat == DataFormatInteger) {
    137             if (node.isConstant()) {
    138                 ASSERT(isInt32Constant(nodeIndex));
    139                 m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), reg);
    140             } else
    141                 m_jit.load32(JITCompiler::addressFor(spillMe), reg);
    142             return;
    143         }
    144 
    145         if (node.isConstant())
    146             m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
    147         else {
    148             ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
    149             m_jit.loadPtr(JITCompiler::addressFor(spillMe), reg);
    150         }
    151     }
    152     void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
    153     {
    154         GenerationInfo& info = m_generationInfo[spillMe];
    155         if (info.fpr() == exclude)
    156             return;
    157 
    158         NodeIndex nodeIndex = info.nodeIndex();
    159         Node& node = m_jit.graph()[nodeIndex];
    160         ASSERT(info.registerFormat() == DataFormatDouble);
    161 
    162         if (node.isConstant()) {
    163             JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
    164             m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
    165         } else {
    166             m_jit.loadPtr(JITCompiler::addressFor(spillMe), JITCompiler::gprToRegisterID(canTrample));
    167             unboxDouble(canTrample, info.fpr());
    168         }
    169     }
    170 
    171     void silentSpillAllRegisters(GPRReg exclude, GPRReg preserve = InvalidGPRReg)
    172     {
    173         GPRReg canTrample = (preserve == gpr0) ? gpr1 : gpr0;
    174 
    175         for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
    176             VirtualRegister name = m_gprs.name(gpr);
    177             if (name != InvalidVirtualRegister)
    178                 silentSpillGPR(name, exclude);
    179         }
    180         for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
    181             VirtualRegister name = m_fprs.name(fpr);
    182             if (name != InvalidVirtualRegister)
    183                 silentSpillFPR(name, canTrample);
    184         }
    185     }
    186     void silentSpillAllRegisters(FPRReg exclude, GPRReg preserve = InvalidGPRReg)
    187     {
    188         GPRReg canTrample = (preserve == gpr0) ? gpr1 : gpr0;
    189 
    190         for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
    191             VirtualRegister name = m_gprs.name(gpr);
    192             if (name != InvalidVirtualRegister)
    193                 silentSpillGPR(name);
    194         }
    195         for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
    196             VirtualRegister name = m_fprs.name(fpr);
    197             if (name != InvalidVirtualRegister)
    198                 silentSpillFPR(name, canTrample, exclude);
    199         }
    200     }
    201     void silentFillAllRegisters(GPRReg exclude)
    202     {
    203         GPRReg canTrample = (exclude == gpr0) ? gpr1 : gpr0;
    204 
    205         for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
    206             VirtualRegister name = m_fprs.name(fpr);
    207             if (name != InvalidVirtualRegister)
    208                 silentFillFPR(name, canTrample);
    209         }
    210         for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
    211             VirtualRegister name = m_gprs.name(gpr);
    212             if (name != InvalidVirtualRegister)
    213                 silentFillGPR(name, exclude);
    214         }
    215     }
    216     void silentFillAllRegisters(FPRReg exclude)
    217     {
    218         GPRReg canTrample = gpr0;
    219 
    220         for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
    221             VirtualRegister name = m_fprs.name(fpr);
    222             if (name != InvalidVirtualRegister) {
    223 #ifndef NDEBUG
    224                 ASSERT(fpr != exclude);
    225 #else
    226                 UNUSED_PARAM(exclude);
    227 #endif
    228                 silentFillFPR(name, canTrample, exclude);
    229             }
    230         }
    231         for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
    232             VirtualRegister name = m_gprs.name(gpr);
    233             if (name != InvalidVirtualRegister)
    234                 silentFillGPR(name);
    235         }
    236     }
    237 
    238     // These methods are used to plant calls out to C++
    239     // helper routines to convert between types.
    240     void valueToNumber(JSValueOperand&, FPRReg result);
    241     void valueToInt32(JSValueOperand&, GPRReg result);
    242     void numberToInt32(FPRReg, GPRReg result);
    243 
    244     // Record an entry location into the non-speculative code path;
    245     // for every bail-out on the speculative path we record information
    246     // to be able to re-enter into the non-speculative one.
    247     void trackEntry(MacroAssembler::Label entry)
    248     {
    249         m_entryLocations.append(EntryLocation(entry, this));
    250     }
    251 
    252     EntryLocationVector m_entryLocations;
    253 };
    254 
    255 } } // namespace JSC::DFG
    256 
    257 #endif
    258 #endif
    259 
    260