/* * Copyright (C) 2011-2018 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. */ #pragma once #include "CallFrame.h" #include "VirtualRegister.h" #include #include namespace JSC { template struct OperandValueTraits; enum OperandKind { ArgumentOperand, LocalOperand }; enum OperandsLikeTag { OperandsLike }; template class Operands { public: Operands() : m_numArguments(0) { } explicit Operands(size_t numArguments, size_t numLocals) : m_numArguments(numArguments) { if (WTF::VectorTraits::needsInitialization) { m_values.resize(numArguments + numLocals); } else { m_values.fill(T(), numArguments + numLocals); } } explicit Operands(size_t numArguments, size_t numLocals, const T& initialValue) : m_numArguments(numArguments) { m_values.fill(initialValue, numArguments + numLocals); } template explicit Operands(OperandsLikeTag, const Operands& other) : m_numArguments(other.numberOfArguments()) { m_values.fill(T(), other.numberOfArguments() + other.numberOfLocals()); } size_t numberOfArguments() const { return m_numArguments; } size_t numberOfLocals() const { return m_values.size() - m_numArguments; } size_t argumentIndex(size_t idx) const { ASSERT(idx < m_numArguments); return idx; } size_t localIndex(size_t idx) const { return m_numArguments + idx; } T& argument(size_t idx) { return m_values[argumentIndex(idx)]; } const T& argument(size_t idx) const { return m_values[argumentIndex(idx)]; } T& local(size_t idx) { return m_values[localIndex(idx)]; } const T& local(size_t idx) const { return m_values[localIndex(idx)]; } template size_t sizeFor() const { if (operandKind == ArgumentOperand) return numberOfArguments(); return numberOfLocals(); } template T& atFor(size_t idx) { if (operandKind == ArgumentOperand) return argument(idx); return local(idx); } template const T& atFor(size_t idx) const { if (operandKind == ArgumentOperand) return argument(idx); return local(idx); } void ensureLocals(size_t size) { size_t oldSize = m_values.size(); size_t newSize = m_numArguments + size; if (newSize <= oldSize) return; m_values.grow(newSize); if (!WTF::VectorTraits::needsInitialization) { for (size_t i = oldSize; i < m_values.size(); ++i) m_values[i] = T(); } } void ensureLocals(size_t size, const T& ensuredValue) { size_t oldSize = m_values.size(); size_t newSize = m_numArguments + size; if (newSize <= oldSize) return; m_values.grow(newSize); for (size_t i = oldSize; i < m_values.size(); ++i) m_values[i] = ensuredValue; } void setLocal(size_t idx, const T& value) { ensureLocals(idx + 1); local(idx) = value; } T getLocal(size_t idx) { return idx >= numberOfLocals() ? T() : local(idx); } void setArgumentFirstTime(size_t idx, const T& value) { ASSERT(m_values[idx] == T()); argument(idx) = value; } void setLocalFirstTime(size_t idx, const T& value) { ASSERT(idx >= numberOfLocals() || local(idx) == T()); setLocal(idx, value); } size_t operandIndex(int operand) const { if (operandIsArgument(operand)) return argumentIndex(VirtualRegister(operand).toArgument()); return localIndex(VirtualRegister(operand).toLocal()); } size_t operandIndex(VirtualRegister virtualRegister) const { return operandIndex(virtualRegister.offset()); } T& operand(int operand) { if (operandIsArgument(operand)) return argument(VirtualRegister(operand).toArgument()); return local(VirtualRegister(operand).toLocal()); } T& operand(VirtualRegister virtualRegister) { return operand(virtualRegister.offset()); } const T& operand(int operand) const { return const_cast(const_cast(this)->operand(operand)); } const T& operand(VirtualRegister operand) const { return const_cast(const_cast(this)->operand(operand)); } bool hasOperand(int operand) const { if (operandIsArgument(operand)) return true; return static_cast(VirtualRegister(operand).toLocal()) < numberOfLocals(); } bool hasOperand(VirtualRegister reg) const { return hasOperand(reg.offset()); } void setOperand(int operand, const T& value) { this->operand(operand) = value; } void setOperand(VirtualRegister virtualRegister, const T& value) { setOperand(virtualRegister.offset(), value); } size_t size() const { return m_values.size(); } const T& at(size_t index) const { return m_values[index]; } T& at(size_t index) { return m_values[index]; } const T& operator[](size_t index) const { return at(index); } T& operator[](size_t index) { return at(index); } bool isArgument(size_t index) const { return index < m_numArguments; } bool isLocal(size_t index) const { return !isArgument(index); } int operandForIndex(size_t index) const { if (index < numberOfArguments()) return virtualRegisterForArgument(index).offset(); return virtualRegisterForLocal(index - numberOfArguments()).offset(); } VirtualRegister virtualRegisterForIndex(size_t index) const { return VirtualRegister(operandForIndex(index)); } void setOperandFirstTime(int operand, const T& value) { if (operandIsArgument(operand)) { setArgumentFirstTime(VirtualRegister(operand).toArgument(), value); return; } setLocalFirstTime(VirtualRegister(operand).toLocal(), value); } void fill(T value) { for (size_t i = 0; i < m_values.size(); ++i) m_values[i] = value; } void clear() { fill(T()); } bool operator==(const Operands& other) const { ASSERT(numberOfArguments() == other.numberOfArguments()); ASSERT(numberOfLocals() == other.numberOfLocals()); return m_values == other.m_values; } void dumpInContext(PrintStream& out, DumpContext* context) const; void dump(PrintStream& out) const; private: // The first m_numArguments of m_values are arguments, the rest are locals. Vector m_values; unsigned m_numArguments; }; } // namespace JSC