| /* |
| * Copyright (C) 2016-2020 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. |
| */ |
| |
| #include "config.h" |
| #include "ArithProfile.h" |
| |
| #include "CCallHelpers.h" |
| #include "JSCJSValueInlines.h" |
| |
| namespace JSC { |
| |
| #if ENABLE(JIT) |
| template<typename BitfieldType> |
| void ArithProfile<BitfieldType>::emitObserveResult(CCallHelpers& jit, JSValueRegs regs, GPRReg tempGPR, TagRegistersMode mode) |
| { |
| if (!shouldEmitSetDouble() && !shouldEmitSetNonNumeric() && !shouldEmitSetHeapBigInt() && !shouldEmitSetBigInt32()) |
| return; |
| |
| CCallHelpers::JumpList done; |
| CCallHelpers::JumpList nonNumeric; |
| |
| done.append(jit.branchIfInt32(regs, mode)); |
| CCallHelpers::Jump notDouble = jit.branchIfNotDoubleKnownNotInt32(regs, mode); |
| emitSetDouble(jit); |
| done.append(jit.jump()); |
| |
| notDouble.link(&jit); |
| |
| #if USE(BIGINT32) |
| CCallHelpers::Jump notBigInt32 = jit.branchIfNotBigInt32(regs, tempGPR, mode); |
| emitSetBigInt32(jit); |
| done.append(jit.jump()); |
| notBigInt32.link(&jit); |
| #else |
| UNUSED_PARAM(tempGPR); |
| #endif |
| |
| nonNumeric.append(jit.branchIfNotCell(regs, mode)); |
| nonNumeric.append(jit.branchIfNotHeapBigInt(regs.payloadGPR())); |
| emitSetHeapBigInt(jit); |
| done.append(jit.jump()); |
| |
| nonNumeric.link(&jit); |
| emitSetNonNumeric(jit); |
| |
| done.link(&jit); |
| } |
| |
| template<typename BitfieldType> |
| bool ArithProfile<BitfieldType>::shouldEmitSetDouble() const |
| { |
| BitfieldType mask = ObservedResults::Int32Overflow | ObservedResults::Int52Overflow | ObservedResults::NegZeroDouble | ObservedResults::NonNegZeroDouble; |
| return (m_bits & mask) != mask; |
| } |
| |
| template<typename BitfieldType> |
| void ArithProfile<BitfieldType>::emitSetDouble(CCallHelpers& jit) const |
| { |
| if (shouldEmitSetDouble()) |
| emitUnconditionalSet(jit, ObservedResults::Int32Overflow | ObservedResults::Int52Overflow | ObservedResults::NegZeroDouble | ObservedResults::NonNegZeroDouble); |
| } |
| |
| template<typename BitfieldType> |
| bool ArithProfile<BitfieldType>::shouldEmitSetNonNumeric() const |
| { |
| BitfieldType mask = ObservedResults::NonNumeric; |
| return (m_bits & mask) != mask; |
| } |
| |
| template<typename BitfieldType> |
| void ArithProfile<BitfieldType>::emitSetNonNumeric(CCallHelpers& jit) const |
| { |
| if (shouldEmitSetNonNumeric()) |
| emitUnconditionalSet(jit, ObservedResults::NonNumeric); |
| } |
| |
| template<typename BitfieldType> |
| bool ArithProfile<BitfieldType>::shouldEmitSetBigInt32() const |
| { |
| #if USE(BIGINT32) |
| BitfieldType mask = ObservedResults::BigInt32; |
| return (m_bits & mask) != mask; |
| #else |
| return false; |
| #endif |
| } |
| |
| template<typename BitfieldType> |
| bool ArithProfile<BitfieldType>::shouldEmitSetHeapBigInt() const |
| { |
| BitfieldType mask = ObservedResults::HeapBigInt; |
| return (m_bits & mask) != mask; |
| } |
| |
| template<typename BitfieldType> |
| void ArithProfile<BitfieldType>::emitSetHeapBigInt(CCallHelpers& jit) const |
| { |
| if (shouldEmitSetHeapBigInt()) |
| emitUnconditionalSet(jit, ObservedResults::HeapBigInt); |
| } |
| |
| #if USE(BIGINT32) |
| template<typename BitfieldType> |
| void ArithProfile<BitfieldType>::emitSetBigInt32(CCallHelpers& jit) const |
| { |
| if (shouldEmitSetBigInt32()) |
| emitUnconditionalSet(jit, ObservedResults::BigInt32); |
| } |
| #endif |
| |
| template<typename BitfieldType> |
| void ArithProfile<BitfieldType>::emitUnconditionalSet(CCallHelpers& jit, BitfieldType mask) const |
| { |
| static_assert(std::is_same<BitfieldType, uint16_t>::value); |
| jit.or16(CCallHelpers::TrustedImm32(mask), CCallHelpers::AbsoluteAddress(addressOfBits())); |
| } |
| |
| // Generate the implementations of the functions above for UnaryArithProfile/BinaryArithProfile |
| // If changing the size of either, add the corresponding lines here. |
| template class ArithProfile<uint16_t>; |
| #endif // ENABLE(JIT) |
| |
| } // namespace JSC |
| |
| namespace WTF { |
| |
| using namespace JSC; |
| |
| template <typename T> |
| void printInternal(PrintStream& out, const ArithProfile<T>& profile) |
| { |
| const char* separator = ""; |
| |
| out.print("Result:<"); |
| if (!profile.didObserveNonInt32()) { |
| out.print("Int32"); |
| separator = "|"; |
| } else { |
| if (profile.didObserveNegZeroDouble()) { |
| out.print(separator, "NegZeroDouble"); |
| separator = "|"; |
| } |
| if (profile.didObserveNonNegZeroDouble()) { |
| out.print(separator, "NonNegZeroDouble"); |
| separator = "|"; |
| } |
| if (profile.didObserveNonNumeric()) { |
| out.print(separator, "NonNumeric"); |
| separator = "|"; |
| } |
| if (profile.didObserveInt32Overflow()) { |
| out.print(separator, "Int32Overflow"); |
| separator = "|"; |
| } |
| if (profile.didObserveInt52Overflow()) { |
| out.print(separator, "Int52Overflow"); |
| separator = "|"; |
| } |
| if (profile.didObserveHeapBigInt()) { |
| out.print(separator, "HeapBigInt"); |
| separator = "|"; |
| } |
| if (profile.didObserveBigInt32()) { |
| out.print(separator, "BigInt32"); |
| separator = "|"; |
| } |
| } |
| out.print(">"); |
| } |
| |
| void printInternal(PrintStream& out, const UnaryArithProfile& profile) |
| { |
| printInternal(out, static_cast<ArithProfile<UnaryArithProfileBase>>(profile)); |
| |
| out.print(" Arg ObservedType:<"); |
| out.print(profile.argObservedType()); |
| out.print(">"); |
| } |
| |
| void printInternal(PrintStream& out, const BinaryArithProfile& profile) |
| { |
| printInternal(out, static_cast<ArithProfile<UnaryArithProfileBase>>(profile)); |
| |
| if (profile.tookSpecialFastPath()) |
| out.print(" Took special fast path."); |
| |
| out.print(" LHS ObservedType:<"); |
| out.print(profile.lhsObservedType()); |
| out.print("> RHS ObservedType:<"); |
| out.print(profile.rhsObservedType()); |
| out.print(">"); |
| } |
| |
| void printInternal(PrintStream& out, const JSC::ObservedType& observedType) |
| { |
| const char* separator = ""; |
| if (observedType.sawInt32()) { |
| out.print(separator, "Int32"); |
| separator = "|"; |
| } |
| if (observedType.sawNumber()) { |
| out.print(separator, "Number"); |
| separator = "|"; |
| } |
| if (observedType.sawNonNumber()) { |
| out.print(separator, "NonNumber"); |
| separator = "|"; |
| } |
| } |
| |
| } // namespace WTF |