/* * Copyright (C) 2013, 2014 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 FTLLocation_h #define FTLLocation_h #if ENABLE(FTL_JIT) #include "FPRInfo.h" #include "FTLDWARFRegister.h" #include "FTLStackMaps.h" #include "GPRInfo.h" #include namespace JSC { namespace FTL { class Location { public: enum Kind { Unprocessed, Register, Indirect, Constant }; Location() : m_kind(Unprocessed) { u.constant = 0; } Location(WTF::HashTableDeletedValueType) : m_kind(Unprocessed) { u.constant = 1; } static Location forRegister(DWARFRegister dwarfReg, int32_t addend) { Location result; result.m_kind = Register; result.u.variable.dwarfRegNum = dwarfReg.dwarfRegNum(); result.u.variable.offset = addend; return result; } static Location forIndirect(DWARFRegister dwarfReg, int32_t offset) { Location result; result.m_kind = Indirect; result.u.variable.dwarfRegNum = dwarfReg.dwarfRegNum(); result.u.variable.offset = offset; return result; } static Location forConstant(int64_t constant) { Location result; result.m_kind = Constant; result.u.constant = constant; return result; } // You can pass a null StackMaps if you are confident that the location doesn't // involve a wide constant. static Location forStackmaps(const StackMaps*, const StackMaps::Location&); Kind kind() const { return m_kind; } bool hasDwarfRegNum() const { return kind() == Register || kind() == Indirect; } int16_t dwarfRegNum() const { ASSERT(hasDwarfRegNum()); return u.variable.dwarfRegNum; } bool hasDwarfReg() const { return hasDwarfRegNum(); } DWARFRegister dwarfReg() const { return DWARFRegister(dwarfRegNum()); } bool hasOffset() const { return kind() == Indirect; } int32_t offset() const { ASSERT(hasOffset()); return u.variable.offset; } bool hasAddend() const { return kind() == Register; } int32_t addend() const { ASSERT(hasAddend()); return u.variable.offset; } bool hasConstant() const { return kind() == Constant; } int64_t constant() const { ASSERT(hasConstant()); return u.constant; } bool operator!() const { return kind() == Unprocessed && !u.variable.offset; } bool isHashTableDeletedValue() const { return kind() == Unprocessed && u.variable.offset; } bool operator==(const Location& other) const { return m_kind == other.m_kind && u.constant == other.u.constant; } unsigned hash() const { unsigned result = m_kind; switch (kind()) { case Unprocessed: result ^= u.variable.offset; break; case Register: result ^= u.variable.dwarfRegNum; break; case Indirect: result ^= u.variable.dwarfRegNum; result ^= u.variable.offset; break; case Constant: result ^= WTF::IntHash::hash(u.constant); break; } return WTF::IntHash::hash(result); } void dump(PrintStream&) const; bool isGPR() const; bool involvesGPR() const; GPRReg gpr() const; GPRReg directGPR() const; // Get the GPR and assert that there is no addend. bool isFPR() const; FPRReg fpr() const; // Assuming that all registers are saved to the savedRegisters buffer according // to FTLSaveRestore convention, this loads the value into the given register. // The code that this generates isn't exactly super fast. This assumes that FP // and SP contain the same values that they would have contained in the original // frame, or that you've done one or more canonically formed calls (i.e. can // restore the FP by following the call frame linked list numFramesToPop times, // and SP can be recovered by popping FP numFramesToPop-1 times and adding 16). void restoreInto(MacroAssembler&, char* savedRegisters, GPRReg result, unsigned numFramesToPop = 0) const; private: Kind m_kind; union { int64_t constant; struct { int16_t dwarfRegNum; int32_t offset; } variable; } u; }; struct LocationHash { static unsigned hash(const Location& key) { return key.hash(); } static bool equal(const Location& a, const Location& b) { return a == b; } static const bool safeToCompareToEmptyOrDeleted = true; }; } } // namespace JSC::FTL namespace WTF { void printInternal(PrintStream&, JSC::FTL::Location::Kind); template struct DefaultHash; template<> struct DefaultHash { typedef JSC::FTL::LocationHash Hash; }; template struct HashTraits; template<> struct HashTraits : SimpleClassHashTraits { }; } // namespace WTF #endif // ENABLE(FTL_JIT) #endif // FTLLocation_h