diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/bytecode/ArithProfile.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/bytecode/ArithProfile.h')
-rw-r--r-- | Source/JavaScriptCore/bytecode/ArithProfile.h | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/bytecode/ArithProfile.h b/Source/JavaScriptCore/bytecode/ArithProfile.h new file mode 100644 index 000000000..40fad1be3 --- /dev/null +++ b/Source/JavaScriptCore/bytecode/ArithProfile.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2016 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 "GPRInfo.h" +#include "JSCJSValue.h" +#include "ResultType.h" +#include "TagRegistersMode.h" + +namespace JSC { + +class CCallHelpers; + +struct ObservedType { + ObservedType(uint8_t bits = TypeEmpty) + : m_bits(bits) + { } + + bool sawInt32() const { return m_bits & TypeInt32; } + bool isOnlyInt32() const { return m_bits == TypeInt32; } + bool sawNumber() const { return m_bits & TypeNumber; } + bool isOnlyNumber() const { return m_bits == TypeNumber; } + bool sawNonNumber() const { return m_bits & TypeNonNumber; } + bool isOnlyNonNumber() const { return m_bits == TypeNonNumber; } + bool isEmpty() const { return !m_bits; } + uint8_t bits() const { return m_bits; } + + ObservedType withInt32() const { return ObservedType(m_bits | TypeInt32); } + ObservedType withNumber() const { return ObservedType(m_bits | TypeNumber); } + ObservedType withNonNumber() const { return ObservedType(m_bits | TypeNonNumber); } + ObservedType withoutNonNumber() const { return ObservedType(m_bits & ~TypeNonNumber); } + + bool operator==(const ObservedType& other) const { return m_bits == other.m_bits; } + + static const uint8_t TypeEmpty = 0x0; + static const uint8_t TypeInt32 = 0x1; + static const uint8_t TypeNumber = 0x02; + static const uint8_t TypeNonNumber = 0x04; + + static const uint32_t numBitsNeeded = 3; + +private: + uint8_t m_bits; +}; + +struct ArithProfile { +private: + static const uint32_t numberOfFlagBits = 5; + static const uint32_t rhsResultTypeShift = numberOfFlagBits; + static const uint32_t lhsResultTypeShift = rhsResultTypeShift + ResultType::numBitsNeeded; + static const uint32_t rhsObservedTypeShift = lhsResultTypeShift + ResultType::numBitsNeeded; + static const uint32_t lhsObservedTypeShift = rhsObservedTypeShift + ObservedType::numBitsNeeded; + + static_assert(ObservedType::numBitsNeeded == 3, "We make a hard assumption about that here."); + static const uint32_t clearRhsObservedTypeBitMask = static_cast<uint32_t>(~((1 << rhsObservedTypeShift) | (1 << (rhsObservedTypeShift + 1)) | (1 << (rhsObservedTypeShift + 2)))); + static const uint32_t clearLhsObservedTypeBitMask = static_cast<uint32_t>(~((1 << lhsObservedTypeShift) | (1 << (lhsObservedTypeShift + 1)) | (1 << (lhsObservedTypeShift + 2)))); + + static const uint32_t resultTypeMask = (1 << ResultType::numBitsNeeded) - 1; + static const uint32_t observedTypeMask = (1 << ObservedType::numBitsNeeded) - 1; +public: + static const uint32_t specialFastPathBit = 1 << (lhsObservedTypeShift + ObservedType::numBitsNeeded); + static_assert((lhsObservedTypeShift + ObservedType::numBitsNeeded) <= (sizeof(uint32_t) * 8) - 1, "Should fit in a uint32_t."); + static_assert(!(specialFastPathBit & ~clearLhsObservedTypeBitMask), "These bits should not intersect."); + static_assert(specialFastPathBit & clearLhsObservedTypeBitMask, "These bits should intersect."); + static_assert(specialFastPathBit > ~clearLhsObservedTypeBitMask, "These bits should not intersect and specialFastPathBit should be a higher bit."); + + ArithProfile(ResultType arg) + { + m_bits = (arg.bits() << lhsResultTypeShift); + ASSERT(lhsResultType().bits() == arg.bits()); + ASSERT(lhsObservedType().isEmpty()); + ASSERT(rhsObservedType().isEmpty()); + } + + ArithProfile(ResultType lhs, ResultType rhs) + { + m_bits = (lhs.bits() << lhsResultTypeShift) | (rhs.bits() << rhsResultTypeShift); + ASSERT(lhsResultType().bits() == lhs.bits() && rhsResultType().bits() == rhs.bits()); + ASSERT(lhsObservedType().isEmpty()); + ASSERT(rhsObservedType().isEmpty()); + } + ArithProfile() = default; + + static ArithProfile fromInt(uint32_t bits) + { + ArithProfile result; + result.m_bits = bits; + return result; + } + + enum ObservedResults { + NonNegZeroDouble = 1 << 0, + NegZeroDouble = 1 << 1, + NonNumber = 1 << 2, + Int32Overflow = 1 << 3, + Int52Overflow = 1 << 4, + }; + + ResultType lhsResultType() const { return ResultType((m_bits >> lhsResultTypeShift) & resultTypeMask); } + ResultType rhsResultType() const { return ResultType((m_bits >> rhsResultTypeShift) & resultTypeMask); } + + ObservedType lhsObservedType() const { return ObservedType((m_bits >> lhsObservedTypeShift) & observedTypeMask); } + ObservedType rhsObservedType() const { return ObservedType((m_bits >> rhsObservedTypeShift) & observedTypeMask); } + void setLhsObservedType(ObservedType type) + { + uint32_t bits = m_bits; + bits &= clearLhsObservedTypeBitMask; + bits |= type.bits() << lhsObservedTypeShift; + m_bits = bits; + ASSERT(lhsObservedType() == type); + } + + void setRhsObservedType(ObservedType type) + { + uint32_t bits = m_bits; + bits &= clearRhsObservedTypeBitMask; + bits |= type.bits() << rhsObservedTypeShift; + m_bits = bits; + ASSERT(rhsObservedType() == type); + } + + bool tookSpecialFastPath() const { return m_bits & specialFastPathBit; } + + bool didObserveNonInt32() const { return hasBits(NonNegZeroDouble | NegZeroDouble | NonNumber); } + bool didObserveDouble() const { return hasBits(NonNegZeroDouble | NegZeroDouble); } + bool didObserveNonNegZeroDouble() const { return hasBits(NonNegZeroDouble); } + bool didObserveNegZeroDouble() const { return hasBits(NegZeroDouble); } + bool didObserveNonNumber() const { return hasBits(NonNumber); } + bool didObserveInt32Overflow() const { return hasBits(Int32Overflow); } + bool didObserveInt52Overflow() const { return hasBits(Int52Overflow); } + + void setObservedNonNegZeroDouble() { setBit(NonNegZeroDouble); } + void setObservedNegZeroDouble() { setBit(NegZeroDouble); } + void setObservedNonNumber() { setBit(NonNumber); } + void setObservedInt32Overflow() { setBit(Int32Overflow); } + void setObservedInt52Overflow() { setBit(Int52Overflow); } + + const void* addressOfBits() const { return &m_bits; } + + void observeResult(JSValue value) + { + if (value.isInt32()) + return; + if (value.isNumber()) { + m_bits |= Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble; + return; + } + m_bits |= NonNumber; + } + + void lhsSawInt32() { setLhsObservedType(lhsObservedType().withInt32()); } + void lhsSawNumber() { setLhsObservedType(lhsObservedType().withNumber()); } + void lhsSawNonNumber() { setLhsObservedType(lhsObservedType().withNonNumber()); } + void rhsSawInt32() { setRhsObservedType(rhsObservedType().withInt32()); } + void rhsSawNumber() { setRhsObservedType(rhsObservedType().withNumber()); } + void rhsSawNonNumber() { setRhsObservedType(rhsObservedType().withNonNumber()); } + + void observeLHS(JSValue lhs) + { + ArithProfile newProfile = *this; + if (lhs.isNumber()) { + if (lhs.isInt32()) + newProfile.lhsSawInt32(); + else + newProfile.lhsSawNumber(); + } else + newProfile.lhsSawNonNumber(); + + m_bits = newProfile.bits(); + } + + void observeLHSAndRHS(JSValue lhs, JSValue rhs) + { + observeLHS(lhs); + + ArithProfile newProfile = *this; + if (rhs.isNumber()) { + if (rhs.isInt32()) + newProfile.rhsSawInt32(); + else + newProfile.rhsSawNumber(); + } else + newProfile.rhsSawNonNumber(); + + m_bits = newProfile.bits(); + } + +#if ENABLE(JIT) + // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble) if it sees a + // double. Sets NonNumber if it sees a non-number. + void emitObserveResult(CCallHelpers&, JSValueRegs, TagRegistersMode = HaveTagRegisters); + + // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble). + bool shouldEmitSetDouble() const; + void emitSetDouble(CCallHelpers&) const; + + // Sets NonNumber. + void emitSetNonNumber(CCallHelpers&) const; + bool shouldEmitSetNonNumber() const; +#endif // ENABLE(JIT) + + uint32_t bits() const { return m_bits; } + +private: + bool hasBits(int mask) const { return m_bits & mask; } + void setBit(int mask) { m_bits |= mask; } + + uint32_t m_bits { 0 }; // We take care to update m_bits only in a single operation. We don't ever store an inconsistent bit representation to it. +}; + +} // namespace JSC + +namespace WTF { + +void printInternal(PrintStream&, const JSC::ArithProfile&); +void printInternal(PrintStream&, const JSC::ObservedType&); + +} // namespace WTF |