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
[GPRInfo::numberOfRegisters
];
57 NodeIndex m_fprInfo
[FPRInfo::numberOfRegisters
];
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();
103 if (registerFormat
== DataFormatInteger
) {
104 m_jit
.orPtr(GPRInfo::tagTypeNumberRegister
, info
.gpr());
105 m_jit
.storePtr(info
.gpr(), JITCompiler::addressFor(spillMe
));
107 ASSERT(registerFormat
& DataFormatJS
|| registerFormat
== DataFormatCell
);
108 m_jit
.storePtr(info
.gpr(), JITCompiler::addressFor(spillMe
));
111 void silentSpillFPR(VirtualRegister spillMe
, GPRReg canTrample
, FPRReg exclude
= InvalidFPRReg
)
113 GenerationInfo
& info
= m_generationInfo
[spillMe
];
114 ASSERT(info
.registerFormat() == DataFormatDouble
);
116 if (!info
.needsSpill() || (info
.fpr() == exclude
))
119 boxDouble(info
.fpr(), canTrample
);
120 m_jit
.storePtr(canTrample
, JITCompiler::addressFor(spillMe
));
123 void silentFillGPR(VirtualRegister spillMe
, GPRReg exclude
= InvalidGPRReg
)
125 GenerationInfo
& info
= m_generationInfo
[spillMe
];
126 if (info
.gpr() == exclude
)
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();
134 if (registerFormat
== DataFormatInteger
) {
135 if (node
.isConstant()) {
136 ASSERT(isInt32Constant(nodeIndex
));
137 m_jit
.move(Imm32(valueOfInt32Constant(nodeIndex
)), info
.gpr());
139 m_jit
.load32(JITCompiler::addressFor(spillMe
), info
.gpr());
143 if (node
.isConstant())
144 m_jit
.move(constantAsJSValueAsImmPtr(nodeIndex
), info
.gpr());
146 ASSERT(registerFormat
& DataFormatJS
|| registerFormat
== DataFormatCell
);
147 m_jit
.loadPtr(JITCompiler::addressFor(spillMe
), info
.gpr());
150 void silentFillFPR(VirtualRegister spillMe
, GPRReg canTrample
, FPRReg exclude
= InvalidFPRReg
)
152 GenerationInfo
& info
= m_generationInfo
[spillMe
];
153 if (info
.fpr() == exclude
)
156 NodeIndex nodeIndex
= info
.nodeIndex();
157 Node
& node
= m_jit
.graph()[nodeIndex
];
158 ASSERT(info
.registerFormat() == DataFormatDouble
);
160 if (node
.isConstant())
161 m_jit
.move(constantAsJSValueAsImmPtr(nodeIndex
), info
.gpr());
163 m_jit
.loadPtr(JITCompiler::addressFor(spillMe
), canTrample
);
164 unboxDouble(canTrample
, info
.fpr());
168 void silentSpillAllRegisters(GPRReg exclude
, GPRReg preserve
= InvalidGPRReg
)
170 GPRReg canTrample
= GPRInfo::regT0
;
171 if (preserve
== GPRInfo::regT0
)
172 canTrample
= GPRInfo::regT1
;
174 for (gpr_iterator iter
= m_gprs
.begin(); iter
!= m_gprs
.end(); ++iter
) {
175 if (iter
.name() != InvalidVirtualRegister
)
176 silentSpillGPR(iter
.name(), exclude
);
178 for (fpr_iterator iter
= m_fprs
.begin(); iter
!= m_fprs
.end(); ++iter
) {
179 if (iter
.name() != InvalidVirtualRegister
)
180 silentSpillFPR(iter
.name(), canTrample
);
183 void silentSpillAllRegisters(FPRReg exclude
, GPRReg preserve
= InvalidGPRReg
)
185 GPRReg canTrample
= GPRInfo::regT0
;
186 if (preserve
== GPRInfo::regT0
)
187 canTrample
= GPRInfo::regT1
;
189 for (gpr_iterator iter
= m_gprs
.begin(); iter
!= m_gprs
.end(); ++iter
) {
190 if (iter
.name() != InvalidVirtualRegister
)
191 silentSpillGPR(iter
.name());
193 for (fpr_iterator iter
= m_fprs
.begin(); iter
!= m_fprs
.end(); ++iter
) {
194 if (iter
.name() != InvalidVirtualRegister
)
195 silentSpillFPR(iter
.name(), canTrample
, exclude
);
198 void silentFillAllRegisters(GPRReg exclude
)
200 GPRReg canTrample
= GPRInfo::regT0
;
201 if (exclude
== GPRInfo::regT0
)
202 canTrample
= GPRInfo::regT1
;
204 for (fpr_iterator iter
= m_fprs
.begin(); iter
!= m_fprs
.end(); ++iter
) {
205 if (iter
.name() != InvalidVirtualRegister
)
206 silentFillFPR(iter
.name(), canTrample
);
208 for (gpr_iterator iter
= m_gprs
.begin(); iter
!= m_gprs
.end(); ++iter
) {
209 if (iter
.name() != InvalidVirtualRegister
)
210 silentFillGPR(iter
.name(), exclude
);
213 void silentFillAllRegisters(FPRReg exclude
)
215 GPRReg canTrample
= GPRInfo::regT0
;
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
);
223 for (gpr_iterator iter
= m_gprs
.begin(); iter
!= m_gprs
.end(); ++iter
) {
224 if (iter
.name() != InvalidVirtualRegister
)
225 silentFillGPR(iter
.name());
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
);
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
)
240 m_entryLocations
.append(EntryLocation(entry
, this));
243 EntryLocationVector m_entryLocations
;
246 } } // namespace JSC::DFG