OSDN Git Service

Merge WebKit at r84325: Initial merge by git.
[android-x86/external-webkit.git] / Source / JavaScriptCore / 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[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.
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         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