| /* |
| * 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; |
| } |
| void initNone(NodeIndex nodeIndex, uint32_t useCount) |
| { |
| m_nodeIndex = nodeIndex; |
| m_useCount = useCount; |
| m_registerFormat = DataFormatNone; |
| m_spillFormat = DataFormatNone; |
| m_canFill = false; |
| } |
| |
| // 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 |