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 33namespace JSC { namespace DFG { 34 35class 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. 41struct 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. 68class NonSpeculativeJIT : public JITCodeGenerator { 69 friend struct EntryLocation; 70public: 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 81private: 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