]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGSpeculativeJIT.h
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / dfg / DFGSpeculativeJIT.h
CommitLineData
14957cd0
A
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
33namespace JSC { namespace DFG {
34
35class SpeculativeJIT;
36
37// This enum describes the types of additional recovery that
38// may need be performed should a speculation check fail.
39enum 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
47class SpeculationRecovery {
48public:
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
60private:
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.
72struct 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[GPRInfo::numberOfRegisters];
89 NodeIndex m_fprInfo[FPRInfo::numberOfRegisters];
90};
91typedef 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.
104class SpeculativeJIT : public JITCodeGenerator {
105 friend struct SpeculationCheck;
106public:
107 SpeculativeJIT(JITCompiler& jit)
108 : JITCodeGenerator(jit, true)
109 , m_compileOkay(true)
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
134private:
135 void compile(Node&);
136 void compile(BasicBlock&);
137
138 void checkArgumentTypes();
139 void initializeVariableTypes();
140
141 bool isDoubleConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
142 {
143 if (!m_jit.isDoubleConstant(nodeIndex))
144 return false;
145 double value = m_jit.valueOfDoubleConstant(nodeIndex);
146
147 int32_t asInt32 = static_cast<int32_t>(value);
148 if (value != asInt32)
149 return false;
150 if (!asInt32 && signbit(value))
151 return false;
152
153 out = asInt32;
154 return true;
155 }
156
157 bool isJSConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
158 {
159 if (!m_jit.isJSConstant(nodeIndex))
160 return false;
161 JSValue value = m_jit.valueOfJSConstant(nodeIndex);
162
163 if (!value.isInt32())
164 return false;
165
166 out = value.asInt32();
167 return true;
168 }
169
170 bool detectPeepHoleBranch()
171 {
172 // Check if the block contains precisely one more node.
173 if (m_compileIndex + 2 != m_jit.graph().m_blocks[m_block]->end)
174 return false;
175
176 // Check if the lastNode is a branch on this node.
177 Node& lastNode = m_jit.graph()[m_compileIndex + 1];
178 return lastNode.op == Branch && lastNode.child1 == m_compileIndex;
179 }
180
181 void compilePeepHoleBranch(Node&, JITCompiler::RelationalCondition);
182
183 // Add a speculation check without additional recovery.
184 void speculationCheck(MacroAssembler::Jump jumpToFail)
185 {
186 m_speculationChecks.append(SpeculationCheck(jumpToFail, this));
187 }
188 // Add a speculation check with additional recovery.
189 void speculationCheck(MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
190 {
191 m_speculationRecoveryList.append(recovery);
192 m_speculationChecks.append(SpeculationCheck(jumpToFail, this, m_speculationRecoveryList.size()));
193 }
194
195 // Called when we statically determine that a speculation will fail.
196 void terminateSpeculativeExecution()
197 {
198 // FIXME: in cases where we can statically determine we're going to bail out from the speculative
199 // JIT we should probably rewind code generation and only produce the non-speculative path.
200 m_compileOkay = false;
201 speculationCheck(m_jit.jump());
202 }
203
204 template<bool strict>
205 GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat);
206
207 // It is possible, during speculative generation, to reach a situation in which we
208 // can statically determine a speculation will fail (for example, when two nodes
209 // will make conflicting speculations about the same operand). In such cases this
210 // flag is cleared, indicating no further code generation should take place.
211 bool m_compileOkay;
212 // This vector tracks bail-outs from the speculative path to the non-speculative one.
213 SpeculationCheckVector m_speculationChecks;
214 // Some bail-outs need to record additional information recording specific recovery
215 // to be performed (for example, on detected overflow from an add, we may need to
216 // reverse the addition if an operand is being overwritten).
217 Vector<SpeculationRecovery, 16> m_speculationRecoveryList;
218};
219
220
221// === Speculative Operand types ===
222//
223// SpeculateIntegerOperand, SpeculateStrictInt32Operand and SpeculateCellOperand.
224//
225// These are used to lock the operands to a node into machine registers within the
226// SpeculativeJIT. The classes operate like those provided by the JITCodeGenerator,
227// however these will perform a speculative check for a more restrictive type than
228// we can statically determine the operand to have. If the operand does not have
229// the requested type, a bail-out to the non-speculative path will be taken.
230
231class SpeculateIntegerOperand {
232public:
233 explicit SpeculateIntegerOperand(SpeculativeJIT* jit, NodeIndex index)
234 : m_jit(jit)
235 , m_index(index)
236 , m_gprOrInvalid(InvalidGPRReg)
237#ifndef NDEBUG
238 , m_format(DataFormatNone)
239#endif
240 {
241 ASSERT(m_jit);
242 if (jit->isFilled(index))
243 gpr();
244 }
245
246 ~SpeculateIntegerOperand()
247 {
248 ASSERT(m_gprOrInvalid != InvalidGPRReg);
249 m_jit->unlock(m_gprOrInvalid);
250 }
251
252 NodeIndex index() const
253 {
254 return m_index;
255 }
256
257 DataFormat format()
258 {
259 gpr(); // m_format is set when m_gpr is locked.
260 ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
261 return m_format;
262 }
263
264 GPRReg gpr()
265 {
266 if (m_gprOrInvalid == InvalidGPRReg)
267 m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format);
268 return m_gprOrInvalid;
269 }
270
271private:
272 SpeculativeJIT* m_jit;
273 NodeIndex m_index;
274 GPRReg m_gprOrInvalid;
275 DataFormat m_format;
276};
277
278class SpeculateStrictInt32Operand {
279public:
280 explicit SpeculateStrictInt32Operand(SpeculativeJIT* jit, NodeIndex index)
281 : m_jit(jit)
282 , m_index(index)
283 , m_gprOrInvalid(InvalidGPRReg)
284 {
285 ASSERT(m_jit);
286 if (jit->isFilled(index))
287 gpr();
288 }
289
290 ~SpeculateStrictInt32Operand()
291 {
292 ASSERT(m_gprOrInvalid != InvalidGPRReg);
293 m_jit->unlock(m_gprOrInvalid);
294 }
295
296 NodeIndex index() const
297 {
298 return m_index;
299 }
300
301 GPRReg gpr()
302 {
303 if (m_gprOrInvalid == InvalidGPRReg)
304 m_gprOrInvalid = m_jit->fillSpeculateIntStrict(index());
305 return m_gprOrInvalid;
306 }
307
308private:
309 SpeculativeJIT* m_jit;
310 NodeIndex m_index;
311 GPRReg m_gprOrInvalid;
312};
313
314class SpeculateCellOperand {
315public:
316 explicit SpeculateCellOperand(SpeculativeJIT* jit, NodeIndex index)
317 : m_jit(jit)
318 , m_index(index)
319 , m_gprOrInvalid(InvalidGPRReg)
320 {
321 ASSERT(m_jit);
322 if (jit->isFilled(index))
323 gpr();
324 }
325
326 ~SpeculateCellOperand()
327 {
328 ASSERT(m_gprOrInvalid != InvalidGPRReg);
329 m_jit->unlock(m_gprOrInvalid);
330 }
331
332 NodeIndex index() const
333 {
334 return m_index;
335 }
336
337 GPRReg gpr()
338 {
339 if (m_gprOrInvalid == InvalidGPRReg)
340 m_gprOrInvalid = m_jit->fillSpeculateCell(index());
341 return m_gprOrInvalid;
342 }
343
344private:
345 SpeculativeJIT* m_jit;
346 NodeIndex m_index;
347 GPRReg m_gprOrInvalid;
348};
349
350
351// === SpeculationCheckIndexIterator ===
352//
353// This class is used by the non-speculative JIT to check which
354// nodes require entry points from the speculative path.
355class SpeculationCheckIndexIterator {
356public:
357 SpeculationCheckIndexIterator(SpeculationCheckVector& speculationChecks)
358 : m_speculationChecks(speculationChecks)
359 , m_iter(m_speculationChecks.begin())
360 , m_end(m_speculationChecks.end())
361 {
362 }
363
364 bool hasCheckAtIndex(NodeIndex nodeIndex)
365 {
366 while (m_iter != m_end) {
367 NodeIndex current = m_iter->m_nodeIndex;
368 if (current >= nodeIndex)
369 return current == nodeIndex;
370 ++m_iter;
371 }
372 return false;
373 }
374
375private:
376 SpeculationCheckVector& m_speculationChecks;
377 SpeculationCheckVector::Iterator m_iter;
378 SpeculationCheckVector::Iterator m_end;
379};
380
381
382} } // namespace JSC::DFG
383
384#endif
385#endif
386