• 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