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
33namespace JSC { namespace DFG {
34
35class 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.
41struct 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.
68class NonSpeculativeJIT : public JITCodeGenerator {
69    friend struct EntryLocation;
70public:
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
81private:
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
260