1/*
2 * Copyright (C) 2016 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 "JSCInlines.h"
31
32namespace JSC {
33
34#if ENABLE(JIT)
35template<typename BitfieldType>
36void ArithProfile<BitfieldType>::emitObserveResult(CCallHelpers& jit, JSValueRegs regs, TagRegistersMode mode)
37{
38 if (!shouldEmitSetDouble() && !shouldEmitSetNonNumeric() && !shouldEmitSetBigInt())
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 nonNumeric.append(jit.branchIfNotCell(regs, mode));
52 nonNumeric.append(jit.branchIfNotBigInt(regs.payloadGPR()));
53 emitSetBigInt(jit);
54 done.append(jit.jump());
55
56 nonNumeric.link(&jit);
57 emitSetNonNumeric(jit);
58
59 done.link(&jit);
60}
61
62template<typename BitfieldType>
63bool ArithProfile<BitfieldType>::shouldEmitSetDouble() const
64{
65 BitfieldType mask = ObservedResults::Int32Overflow | ObservedResults::Int52Overflow | ObservedResults::NegZeroDouble | ObservedResults::NonNegZeroDouble;
66 return (m_bits & mask) != mask;
67}
68
69template<typename BitfieldType>
70void ArithProfile<BitfieldType>::emitSetDouble(CCallHelpers& jit) const
71{
72 if (shouldEmitSetDouble())
73 emitUnconditionalSet(jit, ObservedResults::Int32Overflow | ObservedResults::Int52Overflow | ObservedResults::NegZeroDouble | ObservedResults::NonNegZeroDouble);
74}
75
76template<typename BitfieldType>
77bool ArithProfile<BitfieldType>::shouldEmitSetNonNumeric() const
78{
79 BitfieldType mask = ObservedResults::NonNumeric;
80 return (m_bits & mask) != mask;
81}
82
83template<typename BitfieldType>
84void ArithProfile<BitfieldType>::emitSetNonNumeric(CCallHelpers& jit) const
85{
86 if (shouldEmitSetNonNumeric())
87 emitUnconditionalSet(jit, ObservedResults::NonNumeric);
88}
89
90template<typename BitfieldType>
91bool ArithProfile<BitfieldType>::shouldEmitSetBigInt() const
92{
93 BitfieldType mask = ObservedResults::BigInt;
94 return (m_bits & mask) != mask;
95}
96
97template<typename BitfieldType>
98void ArithProfile<BitfieldType>::emitSetBigInt(CCallHelpers& jit) const
99{
100 if (shouldEmitSetBigInt())
101 emitUnconditionalSet(jit, ObservedResults::BigInt);
102}
103
104template<typename BitfieldType>
105void ArithProfile<BitfieldType>::emitUnconditionalSet(CCallHelpers& jit, BitfieldType mask) const
106{
107 static_assert(std::is_same<BitfieldType, uint16_t>::value);
108 jit.or16(CCallHelpers::TrustedImm32(mask), CCallHelpers::AbsoluteAddress(addressOfBits()));
109}
110
111// Generate the implementations of the functions above for UnaryArithProfile/BinaryArithProfile
112// If changing the size of either, add the corresponding lines here.
113template class ArithProfile<uint16_t>;
114#endif // ENABLE(JIT)
115
116} // namespace JSC
117
118namespace WTF {
119
120using namespace JSC;
121
122template <typename T>
123void printInternal(PrintStream& out, const ArithProfile<T>& profile)
124{
125 const char* separator = "";
126
127 out.print("Result:<");
128 if (!profile.didObserveNonInt32()) {
129 out.print("Int32");
130 separator = "|";
131 } else {
132 if (profile.didObserveNegZeroDouble()) {
133 out.print(separator, "NegZeroDouble");
134 separator = "|";
135 }
136 if (profile.didObserveNonNegZeroDouble()) {
137 out.print(separator, "NonNegZeroDouble");
138 separator = "|";
139 }
140 if (profile.didObserveNonNumeric()) {
141 out.print(separator, "NonNumeric");
142 separator = "|";
143 }
144 if (profile.didObserveInt32Overflow()) {
145 out.print(separator, "Int32Overflow");
146 separator = "|";
147 }
148 if (profile.didObserveInt52Overflow()) {
149 out.print(separator, "Int52Overflow");
150 separator = "|";
151 }
152 if (profile.didObserveBigInt()) {
153 out.print(separator, "BigInt");
154 separator = "|";
155 }
156 }
157 out.print(">");
158}
159
160void printInternal(PrintStream& out, const UnaryArithProfile& profile)
161{
162 printInternal(out, static_cast<ArithProfile<UnaryArithProfileBase>>(profile));
163
164 out.print(" Arg ObservedType:<");
165 out.print(profile.argObservedType());
166 out.print(">");
167}
168
169void printInternal(PrintStream& out, const BinaryArithProfile& profile)
170{
171 printInternal(out, static_cast<ArithProfile<UnaryArithProfileBase>>(profile));
172
173 if (profile.tookSpecialFastPath())
174 out.print(" Took special fast path.");
175
176 out.print(" LHS ObservedType:<");
177 out.print(profile.lhsObservedType());
178 out.print("> RHS ObservedType:<");
179 out.print(profile.rhsObservedType());
180 out.print(">");
181}
182
183void printInternal(PrintStream& out, const JSC::ObservedType& observedType)
184{
185 const char* separator = "";
186 if (observedType.sawInt32()) {
187 out.print(separator, "Int32");
188 separator = "|";
189 }
190 if (observedType.sawNumber()) {
191 out.print(separator, "Number");
192 separator = "|";
193 }
194 if (observedType.sawNonNumber()) {
195 out.print(separator, "NonNumber");
196 separator = "|";
197 }
198}
199
200} // namespace WTF
201