/ bytecode / ArithProfile.cpp
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