• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 DFGGenerationInfo_h
27 #define DFGGenerationInfo_h
28 
29 #if ENABLE(DFG_JIT)
30 
31 #include <dfg/DFGJITCompiler.h>
32 
33 namespace JSC { namespace DFG {
34 
35 // === DataFormat ===
36 //
37 // This enum tracks the current representation in which a value is being held.
38 // Values may be unboxed primitives (int32, double, or cell), or boxed as a JSValue.
39 // For boxed values, we may know the type of boxing that has taken place.
40 // (May also need bool, array, object, string types!)
41 enum DataFormat {
42     DataFormatNone = 0,
43     DataFormatInteger = 1,
44     DataFormatDouble = 2,
45     DataFormatCell = 3,
46     DataFormatJS = 8,
47     DataFormatJSInteger = DataFormatJS | DataFormatInteger,
48     DataFormatJSDouble = DataFormatJS | DataFormatDouble,
49     DataFormatJSCell = DataFormatJS | DataFormatCell,
50 };
51 
52 // === GenerationInfo ===
53 //
54 // This class is used to track the current status of a live values during code generation.
55 // Can provide information as to whether a value is in machine registers, and if so which,
56 // whether a value has been spilled to the RegsiterFile, and if so may be able to provide
57 // details of the format in memory (all values are spilled in a boxed form, but we may be
58 // able to track the type of box), and tracks how many outstanding uses of a value remain,
59 // so that we know when the value is dead and the machine registers associated with it
60 // may be released.
61 class GenerationInfo {
62 public:
GenerationInfo()63     GenerationInfo()
64         : m_nodeIndex(NoNode)
65         , m_useCount(0)
66         , m_registerFormat(DataFormatNone)
67         , m_spillFormat(DataFormatNone)
68         , m_canFill(false)
69     {
70     }
71 
initConstant(NodeIndex nodeIndex,uint32_t useCount)72     void initConstant(NodeIndex nodeIndex, uint32_t useCount)
73     {
74         m_nodeIndex = nodeIndex;
75         m_useCount = useCount;
76         m_registerFormat = DataFormatNone;
77         m_spillFormat = DataFormatNone;
78         m_canFill = true;
79     }
initInteger(NodeIndex nodeIndex,uint32_t useCount,GPRReg gpr)80     void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
81     {
82         m_nodeIndex = nodeIndex;
83         m_useCount = useCount;
84         m_registerFormat = DataFormatInteger;
85         m_spillFormat = DataFormatNone;
86         m_canFill = false;
87         u.gpr = gpr;
88     }
89     void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
90     {
91         ASSERT(format & DataFormatJS);
92 
93         m_nodeIndex = nodeIndex;
94         m_useCount = useCount;
95         m_registerFormat = format;
96         m_spillFormat = DataFormatNone;
97         m_canFill = false;
98         u.gpr = gpr;
99     }
initCell(NodeIndex nodeIndex,uint32_t useCount,GPRReg gpr)100     void initCell(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
101     {
102         m_nodeIndex = nodeIndex;
103         m_useCount = useCount;
104         m_registerFormat = DataFormatCell;
105         m_spillFormat = DataFormatNone;
106         m_canFill = false;
107         u.gpr = gpr;
108     }
initDouble(NodeIndex nodeIndex,uint32_t useCount,FPRReg fpr)109     void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
110     {
111         m_nodeIndex = nodeIndex;
112         m_useCount = useCount;
113         m_registerFormat = DataFormatDouble;
114         m_spillFormat = DataFormatNone;
115         m_canFill = false;
116         u.fpr = fpr;
117     }
initNone(NodeIndex nodeIndex,uint32_t useCount)118     void initNone(NodeIndex nodeIndex, uint32_t useCount)
119     {
120         m_nodeIndex = nodeIndex;
121         m_useCount = useCount;
122         m_registerFormat = DataFormatNone;
123         m_spillFormat = DataFormatNone;
124         m_canFill = false;
125     }
126 
127     // Get the index of the node that produced this value.
nodeIndex()128     NodeIndex nodeIndex() { return m_nodeIndex; }
129 
130     // Mark the value as having been used (decrement the useCount).
131     // Returns true if this was the last use of the value, and any
132     // associated machine registers may be freed.
use()133     bool use()
134     {
135         return !--m_useCount;
136     }
137 
138     // Used to check the operands of operations to see if they are on
139     // their last use; in some cases it may be safe to reuse the same
140     // machine register for the result of the operation.
canReuse()141     bool canReuse()
142     {
143         ASSERT(m_useCount);
144         return m_useCount == 1;
145     }
146 
147     // Get the format of the value in machine registers (or 'none').
registerFormat()148     DataFormat registerFormat() { return m_registerFormat; }
149     // Get the format of the value as it is spilled in the RegisterFile (or 'none').
spillFormat()150     DataFormat spillFormat() { return m_spillFormat; }
151 
152     // Get the machine resister currently holding the value.
gpr()153     GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
fpr()154     FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
155 
156     // Check whether a value needs spilling in order to free up any associated machine registers.
needsSpill()157     bool needsSpill()
158     {
159         // This should only be called on values that are currently in a register.
160         ASSERT(m_registerFormat != DataFormatNone);
161         // Constants do not need spilling, nor do values that have already been
162         // spilled to the RegisterFile.
163         return !m_canFill;
164     }
165 
166     // Called when a VirtualRegister is being spilled to the RegisterFile for the first time.
spill(DataFormat spillFormat)167     void spill(DataFormat spillFormat)
168     {
169         // We shouldn't be spill values that don't need spilling.
170         ASSERT(!m_canFill);
171         ASSERT(m_spillFormat == DataFormatNone);
172         // We should only be spilling values that are currently in machine registers.
173         ASSERT(m_registerFormat != DataFormatNone);
174         // We only spill values that have been boxed as a JSValue; otherwise the GC
175         // would need a way to distinguish cell pointers from numeric primitives.
176         ASSERT(spillFormat & DataFormatJS);
177 
178         m_registerFormat = DataFormatNone;
179         m_spillFormat = spillFormat;
180         m_canFill = true;
181     }
182 
183     // Called on values that don't need spilling (constants and values that have
184     // already been spilled), to mark them as no longer being in machine registers.
setSpilled()185     void setSpilled()
186     {
187         // Should only be called on values that don't need spilling, and are currently in registers.
188         ASSERT(m_canFill && m_registerFormat != DataFormatNone);
189         m_registerFormat = DataFormatNone;
190     }
191 
192     // Record that this value is filled into machine registers,
193     // tracking which registers, and what format the value has.
194     void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
195     {
196         ASSERT(format & DataFormatJS);
197         m_registerFormat = format;
198         u.gpr = gpr;
199     }
fillInteger(GPRReg gpr)200     void fillInteger(GPRReg gpr)
201     {
202         m_registerFormat = DataFormatInteger;
203         u.gpr = gpr;
204     }
fillDouble(FPRReg fpr)205     void fillDouble(FPRReg fpr)
206     {
207         m_registerFormat = DataFormatDouble;
208         u.fpr = fpr;
209     }
210 
211 #ifndef NDEBUG
alive()212     bool alive()
213     {
214         return m_useCount;
215     }
216 #endif
217 
218 private:
219     // The index of the node whose result is stored in this virtual register.
220     // FIXME: Can we remove this? - this is currently only used when collecting
221     // snapshots of the RegisterBank for SpeculationCheck/EntryLocation. Could
222     // investigate storing NodeIndex as the name in RegsiterBank, instead of
223     // VirtualRegister.
224     NodeIndex m_nodeIndex;
225     uint32_t m_useCount;
226     DataFormat m_registerFormat;
227     DataFormat m_spillFormat;
228     bool m_canFill;
229     union {
230         GPRReg gpr;
231         FPRReg fpr;
232     } u;
233 };
234 
235 } } // namespace JSC::DFG
236 
237 #endif
238 #endif
239