summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGGenerationInfo.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGGenerationInfo.h')
-rw-r--r--Source/JavaScriptCore/dfg/DFGGenerationInfo.h327
1 files changed, 327 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGGenerationInfo.h b/Source/JavaScriptCore/dfg/DFGGenerationInfo.h
new file mode 100644
index 000000000..6f0fe3143
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGGenerationInfo.h
@@ -0,0 +1,327 @@
+/*
+ * 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 "DataFormat.h"
+#include <dfg/DFGJITCompiler.h>
+
+namespace JSC { namespace DFG {
+
+// === 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;
+ ASSERT(m_useCount);
+ }
+ 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;
+ ASSERT(m_useCount);
+ }
+#if USE(JSVALUE64)
+ 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;
+ ASSERT(m_useCount);
+ }
+#elif USE(JSVALUE32_64)
+ void initJSValue(NodeIndex nodeIndex, uint32_t useCount, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
+ {
+ ASSERT(format & DataFormatJS);
+
+ m_nodeIndex = nodeIndex;
+ m_useCount = useCount;
+ m_registerFormat = format;
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ u.v.tagGPR = tagGPR;
+ u.v.payloadGPR = payloadGPR;
+ ASSERT(m_useCount);
+ }
+#endif
+ 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;
+ ASSERT(m_useCount);
+ }
+ void initBoolean(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
+ {
+ m_nodeIndex = nodeIndex;
+ m_useCount = useCount;
+ m_registerFormat = DataFormatBoolean;
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ u.gpr = gpr;
+ ASSERT(m_useCount);
+ }
+ void initDouble(NodeIndex nodeIndex, uint32_t useCount, FPRReg fpr)
+ {
+ ASSERT(fpr != InvalidFPRReg);
+ m_nodeIndex = nodeIndex;
+ m_useCount = useCount;
+ m_registerFormat = DataFormatDouble;
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ u.fpr = fpr;
+ ASSERT(m_useCount);
+ }
+ void initStorage(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
+ {
+ m_nodeIndex = nodeIndex;
+ m_useCount = useCount;
+ m_registerFormat = DataFormatStorage;
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ u.gpr = gpr;
+ ASSERT(m_useCount);
+ }
+
+ // 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()
+ {
+ ASSERT(m_useCount);
+ 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; }
+
+ bool isJSFormat(DataFormat expectedFormat)
+ {
+ return JSC::isJSFormat(registerFormat(), expectedFormat) || JSC::isJSFormat(spillFormat(), expectedFormat);
+ }
+
+ bool isJSInteger()
+ {
+ return isJSFormat(DataFormatJSInteger);
+ }
+
+ bool isJSDouble()
+ {
+ return isJSFormat(DataFormatJSDouble);
+ }
+
+ bool isJSCell()
+ {
+ return isJSFormat(DataFormatJSCell);
+ }
+
+ bool isJSBoolean()
+ {
+ return isJSFormat(DataFormatJSBoolean);
+ }
+
+ bool isUnknownJS()
+ {
+ return spillFormat() == DataFormatNone
+ ? registerFormat() == DataFormatJS || registerFormat() == DataFormatNone
+ : spillFormat() == DataFormatJS;
+ }
+
+ // Get the machine resister currently holding the value.
+#if USE(JSVALUE64)
+ GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; }
+ FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; }
+ JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.gpr); }
+#elif USE(JSVALUE32_64)
+ GPRReg gpr() { ASSERT(!(m_registerFormat & DataFormatJS) && m_registerFormat != DataFormatDouble); return u.gpr; }
+ GPRReg tagGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.tagGPR; }
+ GPRReg payloadGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.payloadGPR; }
+ FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble || m_registerFormat == DataFormatJSDouble); return u.fpr; }
+ JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.v.tagGPR, u.v.payloadGPR); }
+#endif
+
+ // 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);
+
+ 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;
+ }
+
+ void killSpilled()
+ {
+ m_spillFormat = DataFormatNone;
+ m_canFill = false;
+ }
+
+ // Record that this value is filled into machine registers,
+ // tracking which registers, and what format the value has.
+#if USE(JSVALUE64)
+ void fillJSValue(GPRReg gpr, DataFormat format = DataFormatJS)
+ {
+ ASSERT(format & DataFormatJS);
+ m_registerFormat = format;
+ u.gpr = gpr;
+ }
+#elif USE(JSVALUE32_64)
+ void fillJSValue(GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS)
+ {
+ ASSERT(format & DataFormatJS);
+ m_registerFormat = format;
+ u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed?
+ u.v.payloadGPR = payloadGPR;
+ }
+ void fillCell(GPRReg gpr)
+ {
+ m_registerFormat = DataFormatCell;
+ u.gpr = gpr;
+ }
+#endif
+ void fillInteger(GPRReg gpr)
+ {
+ m_registerFormat = DataFormatInteger;
+ u.gpr = gpr;
+ }
+ void fillBoolean(GPRReg gpr)
+ {
+ m_registerFormat = DataFormatBoolean;
+ u.gpr = gpr;
+ }
+ void fillDouble(FPRReg fpr)
+ {
+ ASSERT(fpr != InvalidFPRReg);
+ m_registerFormat = DataFormatDouble;
+ u.fpr = fpr;
+ }
+ void fillStorage(GPRReg gpr)
+ {
+ m_registerFormat = DataFormatStorage;
+ u.gpr = gpr;
+ }
+
+ bool alive()
+ {
+ return m_useCount;
+ }
+
+private:
+ // The index of the node whose result is stored in this virtual register.
+ NodeIndex m_nodeIndex;
+ uint32_t m_useCount;
+ DataFormat m_registerFormat;
+ DataFormat m_spillFormat;
+ bool m_canFill;
+ union {
+ GPRReg gpr;
+ FPRReg fpr;
+#if USE(JSVALUE32_64)
+ struct {
+ GPRReg tagGPR;
+ GPRReg payloadGPR;
+ } v;
+#endif
+ } u;
+};
+
+} } // namespace JSC::DFG
+
+#endif
+#endif