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 | |
32 | namespace JSC { |
33 | |
34 | #if ENABLE(JIT) |
35 | template<typename BitfieldType> |
36 | void 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 | |
62 | template<typename BitfieldType> |
63 | bool ArithProfile<BitfieldType>::shouldEmitSetDouble() const |
64 | { |
65 | BitfieldType mask = ObservedResults::Int32Overflow | ObservedResults::Int52Overflow | ObservedResults::NegZeroDouble | ObservedResults::NonNegZeroDouble; |
66 | return (m_bits & mask) != mask; |
67 | } |
68 | |
69 | template<typename BitfieldType> |
70 | void ArithProfile<BitfieldType>::emitSetDouble(CCallHelpers& jit) const |
71 | { |
72 | if (shouldEmitSetDouble()) |
73 | emitUnconditionalSet(jit, ObservedResults::Int32Overflow | ObservedResults::Int52Overflow | ObservedResults::NegZeroDouble | ObservedResults::NonNegZeroDouble); |
74 | } |
75 | |
76 | template<typename BitfieldType> |
77 | bool ArithProfile<BitfieldType>::shouldEmitSetNonNumeric() const |
78 | { |
79 | BitfieldType mask = ObservedResults::NonNumeric; |
80 | return (m_bits & mask) != mask; |
81 | } |
82 | |
83 | template<typename BitfieldType> |
84 | void ArithProfile<BitfieldType>::emitSetNonNumeric(CCallHelpers& jit) const |
85 | { |
86 | if (shouldEmitSetNonNumeric()) |
87 | emitUnconditionalSet(jit, ObservedResults::NonNumeric); |
88 | } |
89 | |
90 | template<typename BitfieldType> |
91 | bool ArithProfile<BitfieldType>::shouldEmitSetBigInt() const |
92 | { |
93 | BitfieldType mask = ObservedResults::BigInt; |
94 | return (m_bits & mask) != mask; |
95 | } |
96 | |
97 | template<typename BitfieldType> |
98 | void ArithProfile<BitfieldType>::emitSetBigInt(CCallHelpers& jit) const |
99 | { |
100 | if (shouldEmitSetBigInt()) |
101 | emitUnconditionalSet(jit, ObservedResults::BigInt); |
102 | } |
103 | |
104 | template<typename BitfieldType> |
105 | void 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. |
113 | template class ArithProfile<uint16_t>; |
114 | #endif // ENABLE(JIT) |
115 | |
116 | } // namespace JSC |
117 | |
118 | namespace WTF { |
119 | |
120 | using namespace JSC; |
121 | |
122 | template <typename T> |
123 | void 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 | |
160 | void 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 | |
169 | void 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 | |
183 | void 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 | |