]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGNonSpeculativeJIT.h
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / dfg / DFGNonSpeculativeJIT.h
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[GPRInfo::numberOfRegisters];
57 NodeIndex m_fprInfo[FPRInfo::numberOfRegisters];
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
103 if (registerFormat == DataFormatInteger) {
104 m_jit.orPtr(GPRInfo::tagTypeNumberRegister, info.gpr());
105 m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
106 } else {
107 ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
108 m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
109 }
110 }
111 void silentSpillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
112 {
113 GenerationInfo& info = m_generationInfo[spillMe];
114 ASSERT(info.registerFormat() == DataFormatDouble);
115
116 if (!info.needsSpill() || (info.fpr() == exclude))
117 return;
118
119 boxDouble(info.fpr(), canTrample);
120 m_jit.storePtr(canTrample, JITCompiler::addressFor(spillMe));
121 }
122
123 void silentFillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
124 {
125 GenerationInfo& info = m_generationInfo[spillMe];
126 if (info.gpr() == exclude)
127 return;
128
129 NodeIndex nodeIndex = info.nodeIndex();
130 Node& node = m_jit.graph()[nodeIndex];
131 ASSERT(info.registerFormat() != DataFormatNone && info.registerFormat() != DataFormatDouble);
132 DataFormat registerFormat = info.registerFormat();
133
134 if (registerFormat == DataFormatInteger) {
135 if (node.isConstant()) {
136 ASSERT(isInt32Constant(nodeIndex));
137 m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), info.gpr());
138 } else
139 m_jit.load32(JITCompiler::addressFor(spillMe), info.gpr());
140 return;
141 }
142
143 if (node.isConstant())
144 m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), info.gpr());
145 else {
146 ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
147 m_jit.loadPtr(JITCompiler::addressFor(spillMe), info.gpr());
148 }
149 }
150 void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
151 {
152 GenerationInfo& info = m_generationInfo[spillMe];
153 if (info.fpr() == exclude)
154 return;
155
156 NodeIndex nodeIndex = info.nodeIndex();
157 Node& node = m_jit.graph()[nodeIndex];
158 ASSERT(info.registerFormat() == DataFormatDouble);
159
160 if (node.isConstant())
161 m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), info.gpr());
162 else {
163 m_jit.loadPtr(JITCompiler::addressFor(spillMe), canTrample);
164 unboxDouble(canTrample, info.fpr());
165 }
166 }
167
168 void silentSpillAllRegisters(GPRReg exclude, GPRReg preserve = InvalidGPRReg)
169 {
170 GPRReg canTrample = GPRInfo::regT0;
171 if (preserve == GPRInfo::regT0)
172 canTrample = GPRInfo::regT1;
173
174 for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
175 if (iter.name() != InvalidVirtualRegister)
176 silentSpillGPR(iter.name(), exclude);
177 }
178 for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
179 if (iter.name() != InvalidVirtualRegister)
180 silentSpillFPR(iter.name(), canTrample);
181 }
182 }
183 void silentSpillAllRegisters(FPRReg exclude, GPRReg preserve = InvalidGPRReg)
184 {
185 GPRReg canTrample = GPRInfo::regT0;
186 if (preserve == GPRInfo::regT0)
187 canTrample = GPRInfo::regT1;
188
189 for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
190 if (iter.name() != InvalidVirtualRegister)
191 silentSpillGPR(iter.name());
192 }
193 for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
194 if (iter.name() != InvalidVirtualRegister)
195 silentSpillFPR(iter.name(), canTrample, exclude);
196 }
197 }
198 void silentFillAllRegisters(GPRReg exclude)
199 {
200 GPRReg canTrample = GPRInfo::regT0;
201 if (exclude == GPRInfo::regT0)
202 canTrample = GPRInfo::regT1;
203
204 for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
205 if (iter.name() != InvalidVirtualRegister)
206 silentFillFPR(iter.name(), canTrample);
207 }
208 for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
209 if (iter.name() != InvalidVirtualRegister)
210 silentFillGPR(iter.name(), exclude);
211 }
212 }
213 void silentFillAllRegisters(FPRReg exclude)
214 {
215 GPRReg canTrample = GPRInfo::regT0;
216
217 for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
218 if (iter.name() != InvalidVirtualRegister) {
219 ASSERT_UNUSED(exclude, iter.regID() != exclude);
220 silentFillFPR(iter.name(), canTrample, exclude);
221 }
222 }
223 for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
224 if (iter.name() != InvalidVirtualRegister)
225 silentFillGPR(iter.name());
226 }
227 }
228
229 // These methods are used to plant calls out to C++
230 // helper routines to convert between types.
231 void valueToNumber(JSValueOperand&, FPRReg result);
232 void valueToInt32(JSValueOperand&, GPRReg result);
233 void numberToInt32(FPRReg, GPRReg result);
234
235 // Record an entry location into the non-speculative code path;
236 // for every bail-out on the speculative path we record information
237 // to be able to re-enter into the non-speculative one.
238 void trackEntry(MacroAssembler::Label entry)
239 {
240 m_entryLocations.append(EntryLocation(entry, this));
241 }
242
243 EntryLocationVector m_entryLocations;
244 };
245
246 } } // namespace JSC::DFG
247
248 #endif
249 #endif
250