ArithProfile.cpp
1 /* 2 * Copyright (C) 2016-2020 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "ArithProfile.h" 28 29 #include "CCallHelpers.h" 30 #include "JSCJSValueInlines.h" 31 32 namespace JSC { 33 34 #if ENABLE(JIT) 35 template<typename BitfieldType> 36 void ArithProfile<BitfieldType>::emitObserveResult(CCallHelpers& jit, JSValueRegs regs, GPRReg tempGPR, TagRegistersMode mode) 37 { 38 if (!shouldEmitSetDouble() && !shouldEmitSetNonNumeric() && !shouldEmitSetHeapBigInt() && !shouldEmitSetBigInt32()) 39 return; 40 41 CCallHelpers::JumpList done; 42 CCallHelpers::JumpList nonNumeric; 43 44 done.append(jit.branchIfInt32(regs, mode)); 45 CCallHelpers::Jump notDouble = jit.branchIfNotDoubleKnownNotInt32(regs, mode); 46 emitSetDouble(jit); 47 done.append(jit.jump()); 48 49 notDouble.link(&jit); 50 51 #if USE(BIGINT32) 52 CCallHelpers::Jump notBigInt32 = jit.branchIfNotBigInt32(regs, tempGPR, mode); 53 emitSetBigInt32(jit); 54 done.append(jit.jump()); 55 notBigInt32.link(&jit); 56 #else 57 UNUSED_PARAM(tempGPR); 58 #endif 59 60 nonNumeric.append(jit.branchIfNotCell(regs, mode)); 61 nonNumeric.append(jit.branchIfNotHeapBigInt(regs.payloadGPR())); 62 emitSetHeapBigInt(jit); 63 done.append(jit.jump()); 64 65 nonNumeric.link(&jit); 66 emitSetNonNumeric(jit); 67 68 done.link(&jit); 69 } 70 71 template<typename BitfieldType> 72 bool ArithProfile<BitfieldType>::shouldEmitSetDouble() const 73 { 74 BitfieldType mask = ObservedResults::Int32Overflow | ObservedResults::Int52Overflow | ObservedResults::NegZeroDouble | ObservedResults::NonNegZeroDouble; 75 return (m_bits & mask) != mask; 76 } 77 78 template<typename BitfieldType> 79 void ArithProfile<BitfieldType>::emitSetDouble(CCallHelpers& jit) const 80 { 81 if (shouldEmitSetDouble()) 82 emitUnconditionalSet(jit, ObservedResults::Int32Overflow | ObservedResults::Int52Overflow | ObservedResults::NegZeroDouble | ObservedResults::NonNegZeroDouble); 83 } 84 85 template<typename BitfieldType> 86 bool ArithProfile<BitfieldType>::shouldEmitSetNonNumeric() const 87 { 88 BitfieldType mask = ObservedResults::NonNumeric; 89 return (m_bits & mask) != mask; 90 } 91 92 template<typename BitfieldType> 93 void ArithProfile<BitfieldType>::emitSetNonNumeric(CCallHelpers& jit) const 94 { 95 if (shouldEmitSetNonNumeric()) 96 emitUnconditionalSet(jit, ObservedResults::NonNumeric); 97 } 98 99 template<typename BitfieldType> 100 bool ArithProfile<BitfieldType>::shouldEmitSetBigInt32() const 101 { 102 #if USE(BIGINT32) 103 BitfieldType mask = ObservedResults::BigInt32; 104 return (m_bits & mask) != mask; 105 #else 106 return false; 107 #endif 108 } 109 110 template<typename BitfieldType> 111 bool ArithProfile<BitfieldType>::shouldEmitSetHeapBigInt() const 112 { 113 BitfieldType mask = ObservedResults::HeapBigInt; 114 return (m_bits & mask) != mask; 115 } 116 117 template<typename BitfieldType> 118 void ArithProfile<BitfieldType>::emitSetHeapBigInt(CCallHelpers& jit) const 119 { 120 if (shouldEmitSetHeapBigInt()) 121 emitUnconditionalSet(jit, ObservedResults::HeapBigInt); 122 } 123 124 #if USE(BIGINT32) 125 template<typename BitfieldType> 126 void ArithProfile<BitfieldType>::emitSetBigInt32(CCallHelpers& jit) const 127 { 128 if (shouldEmitSetBigInt32()) 129 emitUnconditionalSet(jit, ObservedResults::BigInt32); 130 } 131 #endif 132 133 template<typename BitfieldType> 134 void ArithProfile<BitfieldType>::emitUnconditionalSet(CCallHelpers& jit, BitfieldType mask) const 135 { 136 static_assert(std::is_same<BitfieldType, uint16_t>::value); 137 jit.or16(CCallHelpers::TrustedImm32(mask), CCallHelpers::AbsoluteAddress(addressOfBits())); 138 } 139 140 // Generate the implementations of the functions above for UnaryArithProfile/BinaryArithProfile 141 // If changing the size of either, add the corresponding lines here. 142 template class ArithProfile<uint16_t>; 143 #endif // ENABLE(JIT) 144 145 } // namespace JSC 146 147 namespace WTF { 148 149 using namespace JSC; 150 151 template <typename T> 152 void printInternal(PrintStream& out, const ArithProfile<T>& profile) 153 { 154 const char* separator = ""; 155 156 out.print("Result:<"); 157 if (!profile.didObserveNonInt32()) { 158 out.print("Int32"); 159 separator = "|"; 160 } else { 161 if (profile.didObserveNegZeroDouble()) { 162 out.print(separator, "NegZeroDouble"); 163 separator = "|"; 164 } 165 if (profile.didObserveNonNegZeroDouble()) { 166 out.print(separator, "NonNegZeroDouble"); 167 separator = "|"; 168 } 169 if (profile.didObserveNonNumeric()) { 170 out.print(separator, "NonNumeric"); 171 separator = "|"; 172 } 173 if (profile.didObserveInt32Overflow()) { 174 out.print(separator, "Int32Overflow"); 175 separator = "|"; 176 } 177 if (profile.didObserveInt52Overflow()) { 178 out.print(separator, "Int52Overflow"); 179 separator = "|"; 180 } 181 if (profile.didObserveHeapBigInt()) { 182 out.print(separator, "HeapBigInt"); 183 separator = "|"; 184 } 185 if (profile.didObserveBigInt32()) { 186 out.print(separator, "BigInt32"); 187 separator = "|"; 188 } 189 } 190 out.print(">"); 191 } 192 193 void printInternal(PrintStream& out, const UnaryArithProfile& profile) 194 { 195 printInternal(out, static_cast<ArithProfile<UnaryArithProfileBase>>(profile)); 196 197 out.print(" Arg ObservedType:<"); 198 out.print(profile.argObservedType()); 199 out.print(">"); 200 } 201 202 void printInternal(PrintStream& out, const BinaryArithProfile& profile) 203 { 204 printInternal(out, static_cast<ArithProfile<UnaryArithProfileBase>>(profile)); 205 206 if (profile.tookSpecialFastPath()) 207 out.print(" Took special fast path."); 208 209 out.print(" LHS ObservedType:<"); 210 out.print(profile.lhsObservedType()); 211 out.print("> RHS ObservedType:<"); 212 out.print(profile.rhsObservedType()); 213 out.print(">"); 214 } 215 216 void printInternal(PrintStream& out, const JSC::ObservedType& observedType) 217 { 218 const char* separator = ""; 219 if (observedType.sawInt32()) { 220 out.print(separator, "Int32"); 221 separator = "|"; 222 } 223 if (observedType.sawNumber()) { 224 out.print(separator, "Number"); 225 separator = "|"; 226 } 227 if (observedType.sawNonNumber()) { 228 out.print(separator, "NonNumber"); 229 separator = "|"; 230 } 231 } 232 233 } // namespace WTF