/* * 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 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