2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef DFGNonSpeculativeJIT_h
27 #define DFGNonSpeculativeJIT_h
31 #include <dfg/DFGJITCodeGenerator.h>
33 namespace JSC { namespace DFG {
35 class SpeculationCheckIndexIterator;
37 // === EntryLocation ===
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*);
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;
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.
56 RegisterInfo m_gprInfo[numberOfGPRs];
57 NodeIndex m_fprInfo[numberOfFPRs];
60 // === NonSpeculativeJIT ===
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;
71 NonSpeculativeJIT(JITCompiler& jit)
72 : JITCodeGenerator(jit, false)
76 void compile(SpeculationCheckIndexIterator&);
78 typedef SegmentedVector<EntryLocation, 16> EntryLocationVector;
79 EntryLocationVector& entryLocations() { return m_entryLocations; }
82 void compile(SpeculationCheckIndexIterator&, Node&);
83 void compile(SpeculationCheckIndexIterator&, BasicBlock&);
85 bool isKnownInteger(NodeIndex);
86 bool isKnownNumeric(NodeIndex);
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)
95 GenerationInfo& info = m_generationInfo[spillMe];
96 ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
98 if (!info.needsSpill() || (info.gpr() == exclude))
101 DataFormat registerFormat = info.registerFormat();
102 JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
104 if (registerFormat == DataFormatInteger) {
105 m_jit.orPtr(JITCompiler::tagTypeNumberRegister, reg);
106 m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
108 ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
109 m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
112 void silentSpillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
114 GenerationInfo& info = m_generationInfo[spillMe];
115 ASSERT(info.registerFormat() == DataFormatDouble);
117 if (!info.needsSpill() || (info.fpr() == exclude))
120 boxDouble(info.fpr(), canTrample);
121 m_jit.storePtr(JITCompiler::gprToRegisterID(canTrample), JITCompiler::addressFor(spillMe));
124 void silentFillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
126 GenerationInfo& info = m_generationInfo[spillMe];
127 if (info.gpr() == exclude)
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());
136 if (registerFormat == DataFormatInteger) {
137 if (node.isConstant()) {
138 ASSERT(isInt32Constant(nodeIndex));
139 m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), reg);
141 m_jit.load32(JITCompiler::addressFor(spillMe), reg);
145 if (node.isConstant())
146 m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
148 ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
149 m_jit.loadPtr(JITCompiler::addressFor(spillMe), reg);
152 void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
154 GenerationInfo& info = m_generationInfo[spillMe];
155 if (info.fpr() == exclude)
158 NodeIndex nodeIndex = info.nodeIndex();
159 Node& node = m_jit.graph()[nodeIndex];
160 ASSERT(info.registerFormat() == DataFormatDouble);
162 if (node.isConstant()) {
163 JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(info.gpr());
164 m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
166 m_jit.loadPtr(JITCompiler::addressFor(spillMe), JITCompiler::gprToRegisterID(canTrample));
167 unboxDouble(canTrample, info.fpr());
171 void silentSpillAllRegisters(GPRReg exclude, GPRReg preserve = InvalidGPRReg)
173 GPRReg canTrample = (preserve == gpr0) ? gpr1 : gpr0;
175 for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
176 VirtualRegister name = m_gprs.name(gpr);
177 if (name != InvalidVirtualRegister)
178 silentSpillGPR(name, exclude);
180 for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
181 VirtualRegister name = m_fprs.name(fpr);
182 if (name != InvalidVirtualRegister)
183 silentSpillFPR(name, canTrample);
186 void silentSpillAllRegisters(FPRReg exclude, GPRReg preserve = InvalidGPRReg)
188 GPRReg canTrample = (preserve == gpr0) ? gpr1 : gpr0;
190 for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
191 VirtualRegister name = m_gprs.name(gpr);
192 if (name != InvalidVirtualRegister)
193 silentSpillGPR(name);
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);
201 void silentFillAllRegisters(GPRReg exclude)
203 GPRReg canTrample = (exclude == gpr0) ? gpr1 : gpr0;
205 for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
206 VirtualRegister name = m_fprs.name(fpr);
207 if (name != InvalidVirtualRegister)
208 silentFillFPR(name, canTrample);
210 for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
211 VirtualRegister name = m_gprs.name(gpr);
212 if (name != InvalidVirtualRegister)
213 silentFillGPR(name, exclude);
216 void silentFillAllRegisters(FPRReg exclude)
218 GPRReg canTrample = gpr0;
220 for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
221 VirtualRegister name = m_fprs.name(fpr);
222 if (name != InvalidVirtualRegister) {
224 ASSERT(fpr != exclude);
226 UNUSED_PARAM(exclude);
228 silentFillFPR(name, canTrample, exclude);
231 for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
232 VirtualRegister name = m_gprs.name(gpr);
233 if (name != InvalidVirtualRegister)
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);
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)
249 m_entryLocations.append(EntryLocation(entry, this));
252 EntryLocationVector m_entryLocations;
255 } } // namespace JSC::DFG