|  | /* | 
|  | * Copyright (C) 2013-2015 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 | 
|  |  | 
|  | #if ENABLE(FTL_JIT) | 
|  |  | 
|  | #include "DFGCommon.h" | 
|  | #include "FPRInfo.h" | 
|  | #include "GPRInfo.h" | 
|  | #include "Reg.h" | 
|  | #include <wtf/HashMap.h> | 
|  |  | 
|  | namespace JSC { | 
|  |  | 
|  | namespace B3 { | 
|  | class ValueRep; | 
|  | } // namespace B3 | 
|  |  | 
|  | 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(Reg reg, int32_t addend) | 
|  | { | 
|  | Location result; | 
|  | result.m_kind = Register; | 
|  | result.u.variable.regIndex = reg.index(); | 
|  | result.u.variable.offset = addend; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static Location forIndirect(Reg reg, int32_t offset) | 
|  | { | 
|  | Location result; | 
|  | result.m_kind = Indirect; | 
|  | result.u.variable.regIndex = reg.index(); | 
|  | 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; | 
|  | } | 
|  |  | 
|  | static Location forValueRep(const B3::ValueRep&); | 
|  |  | 
|  | Kind kind() const { return m_kind; } | 
|  |  | 
|  | bool hasReg() const { return kind() == Register || kind() == Indirect; } | 
|  | Reg reg() const | 
|  | { | 
|  | ASSERT(hasReg()); | 
|  | return Reg::fromIndex(u.variable.regIndex); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | explicit operator bool() const { return kind() != Unprocessed || u.variable.offset; } | 
|  |  | 
|  | bool operator!() const { return !static_cast<bool>(*this); } | 
|  |  | 
|  | 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.regIndex; | 
|  | break; | 
|  |  | 
|  | case Indirect: | 
|  | result ^= u.variable.regIndex; | 
|  | result ^= u.variable.offset; | 
|  | break; | 
|  |  | 
|  | case Constant: | 
|  | result ^= WTF::IntHash<int64_t>::hash(u.constant); | 
|  | break; | 
|  | } | 
|  |  | 
|  | return WTF::IntHash<unsigned>::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 { | 
|  | unsigned regIndex; | 
|  | 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<typename T> struct DefaultHash; | 
|  | template<> struct DefaultHash<JSC::FTL::Location> { | 
|  | typedef JSC::FTL::LocationHash Hash; | 
|  | }; | 
|  |  | 
|  | template<typename T> struct HashTraits; | 
|  | template<> struct HashTraits<JSC::FTL::Location> : SimpleClassHashTraits<JSC::FTL::Location> { }; | 
|  |  | 
|  | } // namespace WTF | 
|  |  | 
|  | #endif // ENABLE(FTL_JIT) |