1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DFGGenerationInfo_h
#define DFGGenerationInfo_h
#if ENABLE(DFG_JIT)
#include <dfg/DFGJITCompiler.h>
namespace JSC { namespace DFG {
// === DataFormat ===
//
// This enum tracks the current representation in which a value is being held.
// Values may be unboxed primitives (int32, double, or cell), or boxed as a JSValue.
// For boxed values, we may know the type of boxing that has taken place.
// (May also need bool, array, object, string types!)
enum DataFormat {
DataFormatNone = 0,
DataFormatInteger = 1,
DataFormatDouble = 2,
DataFormatCell = 3,
DataFormatJS = 8,
DataFormatJSInteger = DataFormatJS | DataFormatInteger,
DataFormatJSDouble = DataFormatJS | DataFormatDouble,
DataFormatJSCell = DataFormatJS | DataFormatCell,
};
// === GenerationInfo ===
//
// This class is used to track the current status of a live values during code generation.
// Can provide information as to whether a value is in machine registers, and if so which,
// whether a value has been spilled to the RegsiterFile, and if so may be able to provide
// details of the format in memory (all values are spilled in a boxed form, but we may be
// able to track the type of box), and tracks how many outstanding uses of a value remain,
// so that we know when the value is dead and the machine registers associated with it
// may be released.
class GenerationInfo {
public:
GenerationInfo()
: m_nodeIndex(NoNode)
, m_useCount(0)
, m_registerFormat(DataFormatNone)
, m_spillFormat(DataFormatNone)
, m_canFill(false)
{
}
void initConstant(NodeIndex nodeIndex, uint32_t useCount)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatNone;
m_spillFormat = DataFormatNone;
m_canFill = true;
}
void initInteger(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatInteger;
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
}
void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS)
{
ASSERT(format & DataFormatJS);
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = format;
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
}
void initCell(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatCell;
m_spillFormat = DataFormatNone;
m_canFill = false;
u.gpr = gpr;
}
void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
{
m_nodeIndex = nodeIndex;
m_useCount = useCount;
m_registerFormat = DataFormatDouble;
m_spillFormat = DataFormatNone;
m_canFill = false;
u.fpr = fpr;
}
// Get the index of the node that produced this value.
NodeIndex nodeIndex() { return m_nodeIndex; }
// Mark the value as having been used (decrement the useCount).
// Returns true if this was the last use of the value, and any
// associated machine registers may be freed.
bool use()
{
return !--m_useCount;
}
// Used to check the operands of operations to see if they are on
// their last use; in some cases it may be safe to reuse the same
// machine register for the result of the operation.
bool canReuse()
{
ASSERT(m_useCount);
return m_useCount == 1;
}
// Get the format of the value in machine registers (or 'none').
DataFormat registerFormat() { return m_registerFormat; }
// Get the format of the value as it is spilled in the RegisterFile (or 'none').
DataFormat spillFormat() { return m_spillFormat; }
// Get the machine resister currently holding the value.
GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
// Check whether a value needs spilling in order to free up any associated machine registers.
bool needsSpill()
{
// This should only be called on values that are currently in a register.
ASSERT(m_registerFormat != DataFormatNone);
// Constants do not need spilling, nor do values that have already been
// spilled to the RegisterFile.
return !m_canFill;
}
// Called when a VirtualRegister is being spilled to the RegisterFile for the first time.
void spill(DataFormat spillFormat)
{
// We shouldn't be spill values that don't need spilling.
ASSERT(!m_canFill);
ASSERT(m_spillFormat == DataFormatNone);
// We should only be spilling values that are currently in machine registers.
ASSERT(m_registerFormat != DataFormatNone);
// We only spill values that have been boxed as a JSValue; otherwise the GC
// would need a way to distinguish cell pointers from numeric primitives.
ASSERT(spillFormat & DataFormatJS);
m_registerFormat = DataFormatNone;
m_spillFormat = spillFormat;
m_canFill = true;
}
// Called on values that don't need spilling (constants and values that have
// already been spilled), to mark them as no longer being in machine registers.
void setSpilled()
{
// Should only be called on values that don't need spilling, and are currently in registers.
ASSERT(m_canFill && m_registerFormat != DataFormatNone);
m_registerFormat = DataFormatNone;
}
// Record that this value is filled into machine registers,
// tracking which registers, and what format the value has.
void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
{
ASSERT(format & DataFormatJS);
m_registerFormat = format;
u.gpr = gpr;
}
void fillInteger(GPRReg gpr)
{
m_registerFormat = DataFormatInteger;
u.gpr = gpr;
}
void fillDouble(FPRReg fpr)
{
m_registerFormat = DataFormatDouble;
u.fpr = fpr;
}
#ifndef NDEBUG
bool alive()
{
return m_useCount;
}
#endif
private:
// The index of the node whose result is stored in this virtual register.
// FIXME: Can we remove this? - this is currently only used when collecting
// snapshots of the RegisterBank for SpeculationCheck/EntryLocation. Could
// investigate storing NodeIndex as the name in RegsiterBank, instead of
// VirtualRegister.
NodeIndex m_nodeIndex;
uint32_t m_useCount;
DataFormat m_registerFormat;
DataFormat m_spillFormat;
bool m_canFill;
union {
GPRReg gpr;
FPRReg fpr;
} u;
};
} } // namespace JSC::DFG
#endif
#endif
|