/* * Copyright (C) 2011, 2012 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 Operands_h #define Operands_h #include "CallFrame.h" #include "JSObject.h" #include "ScopeChain.h" #include namespace JSC { // argument 0 is 'this'. inline bool operandIsArgument(int operand) { return operand < 0; } inline int operandToArgument(int operand) { return -operand + CallFrame::thisArgumentOffset(); } inline int argumentToOperand(int argument) { return -argument + CallFrame::thisArgumentOffset(); } template struct OperandValueTraits; template struct OperandValueTraits { static T defaultValue() { return T(); } static void dump(const T& value, FILE* out) { value.dump(out); } }; template > class Operands { public: Operands() { } explicit Operands(size_t numArguments, size_t numLocals) { m_arguments.fill(Traits::defaultValue(), numArguments); m_locals.fill(Traits::defaultValue(), numLocals); } size_t numberOfArguments() const { return m_arguments.size(); } size_t numberOfLocals() const { return m_locals.size(); } T& argument(size_t idx) { return m_arguments[idx]; } const T& argument(size_t idx) const { return m_arguments[idx]; } T& local(size_t idx) { return m_locals[idx]; } const T& local(size_t idx) const { return m_locals[idx]; } void ensureLocals(size_t size) { if (size <= m_locals.size()) return; size_t oldSize = m_locals.size(); m_locals.resize(size); for (size_t i = oldSize; i < m_locals.size(); ++i) m_locals[i] = Traits::defaultValue(); } void setLocal(size_t idx, const T& value) { ensureLocals(idx + 1); m_locals[idx] = value; } T getLocal(size_t idx) { if (idx >= m_locals.size()) return Traits::defaultValue(); return m_locals[idx]; } void setArgumentFirstTime(size_t idx, const T& value) { ASSERT(m_arguments[idx] == Traits::defaultValue()); argument(idx) = value; } void setLocalFirstTime(size_t idx, const T& value) { ASSERT(idx >= m_locals.size() || m_locals[idx] == Traits::defaultValue()); setLocal(idx, value); } T& operand(int operand) { if (operandIsArgument(operand)) { int argument = operandToArgument(operand); return m_arguments[argument]; } return m_locals[operand]; } const T& operand(int operand) const { return const_cast(const_cast(this)->operand(operand)); } bool hasOperand(int operand) const { if (operandIsArgument(operand)) return true; return static_cast(operand) < numberOfLocals(); } void setOperand(int operand, const T& value) { if (operandIsArgument(operand)) { int argument = operandToArgument(operand); m_arguments[argument] = value; return; } setLocal(operand, value); } size_t size() const { return numberOfArguments() + numberOfLocals(); } const T& at(size_t index) const { if (index < numberOfArguments()) return m_arguments[index]; return m_locals[index - numberOfArguments()]; } T& at(size_t index) { if (index < numberOfArguments()) return m_arguments[index]; return m_locals[index - numberOfArguments()]; } 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 < numberOfArguments(); } bool isVariable(size_t index) const { return !isArgument(index); } int argumentForIndex(size_t index) const { return index; } int variableForIndex(size_t index) const { return index - m_arguments.size(); } int operandForIndex(size_t index) const { if (index < numberOfArguments()) return argumentToOperand(index); return index - numberOfArguments(); } void setOperandFirstTime(int operand, const T& value) { if (operandIsArgument(operand)) { setArgumentFirstTime(operandToArgument(operand), value); return; } setLocalFirstTime(operand, value); } void clear() { for (size_t i = 0; i < m_arguments.size(); ++i) m_arguments[i] = Traits::defaultValue(); for (size_t i = 0; i < m_locals.size(); ++i) m_locals[i] = Traits::defaultValue(); } private: Vector m_arguments; Vector m_locals; }; template void dumpOperands(Operands& operands, FILE* out) { for (size_t argument = 0; argument < operands.numberOfArguments(); ++argument) { if (argument) fprintf(out, " "); Traits::dump(operands.argument(argument), out); } fprintf(out, " : "); for (size_t local = 0; local < operands.numberOfLocals(); ++local) { if (local) fprintf(out, " "); Traits::dump(operands.local(local), out); } } template void dumpOperands(const Operands& operands, FILE* out) { // Use const-cast because: // 1) I don't feel like writing this code twice, and // 2) Some dump() methods may not be const, and I don't really care if that's // the case. dumpOperands(*const_cast*>(&operands), out); } } // namespace JSC #endif // Operands_h