1/*
2 * Copyright (C) 2011-2015 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#pragma once
27
28#if ENABLE(DFG_JIT)
29
30#include "DFGCommon.h"
31#include "DFGDoubleFormatState.h"
32#include "DFGFlushFormat.h"
33#include "DFGFlushedAt.h"
34#include "DFGNodeFlags.h"
35#include "Operands.h"
36#include "SpeculatedType.h"
37#include "VirtualRegister.h"
38#include <wtf/UnionFind.h>
39
40namespace JSC { namespace DFG {
41
42struct Node;
43
44enum DoubleBallot { VoteValue, VoteDouble };
45
46class VariableAccessData : public UnionFind<VariableAccessData> {
47 WTF_MAKE_FAST_ALLOCATED;
48 WTF_MAKE_NONCOPYABLE(VariableAccessData);
49public:
50 VariableAccessData();
51 VariableAccessData(VirtualRegister local);
52
53 VirtualRegister local()
54 {
55 ASSERT(m_local == find()->m_local);
56 return m_local;
57 }
58
59 VirtualRegister& machineLocal()
60 {
61 ASSERT(find() == this);
62 return m_machineLocal;
63 }
64
65 bool mergeIsProfitableToUnbox(bool isProfitableToUnbox)
66 {
67 return checkAndSet(m_isProfitableToUnbox, m_isProfitableToUnbox || isProfitableToUnbox);
68 }
69
70 bool isProfitableToUnbox()
71 {
72 return m_isProfitableToUnbox;
73 }
74
75 bool mergeShouldNeverUnbox(bool shouldNeverUnbox);
76
77 // Returns true if it would be unsound to store the value in an unboxed fashion.
78 // If this returns false, it simply means that it is sound to unbox; it doesn't
79 // mean that we have actually done so.
80 bool shouldNeverUnbox()
81 {
82 return m_shouldNeverUnbox;
83 }
84
85 // Returns true if we should be unboxing the value provided that the predictions
86 // and double format vote say so. This may return false even if shouldNeverUnbox()
87 // returns false, since this incorporates heuristics of profitability.
88 bool shouldUnboxIfPossible()
89 {
90 return !shouldNeverUnbox() && isProfitableToUnbox();
91 }
92
93 bool mergeStructureCheckHoistingFailed(bool failed)
94 {
95 return checkAndSet(m_structureCheckHoistingFailed, m_structureCheckHoistingFailed || failed);
96 }
97
98 bool mergeCheckArrayHoistingFailed(bool failed)
99 {
100 return checkAndSet(m_checkArrayHoistingFailed, m_checkArrayHoistingFailed || failed);
101 }
102
103 bool structureCheckHoistingFailed()
104 {
105 return m_structureCheckHoistingFailed;
106 }
107
108 bool checkArrayHoistingFailed()
109 {
110 return m_checkArrayHoistingFailed;
111 }
112
113 bool mergeIsLoadedFrom(bool isLoadedFrom)
114 {
115 return checkAndSet(m_isLoadedFrom, m_isLoadedFrom || isLoadedFrom);
116 }
117
118 void setIsLoadedFrom(bool isLoadedFrom)
119 {
120 m_isLoadedFrom = isLoadedFrom;
121 }
122
123 bool isLoadedFrom()
124 {
125 return m_isLoadedFrom;
126 }
127
128 bool predict(SpeculatedType prediction);
129
130 SpeculatedType nonUnifiedPrediction()
131 {
132 return m_prediction;
133 }
134
135 SpeculatedType prediction()
136 {
137 return find()->m_prediction;
138 }
139
140 SpeculatedType argumentAwarePrediction()
141 {
142 return find()->m_argumentAwarePrediction;
143 }
144
145 bool mergeArgumentAwarePrediction(SpeculatedType prediction);
146
147 void clearVotes()
148 {
149 ASSERT(find() == this);
150 m_votes[0] = 0;
151 m_votes[1] = 0;
152 }
153
154 void vote(unsigned ballot, float weight = 1)
155 {
156 ASSERT(ballot < 2);
157 m_votes[ballot] += weight;
158 }
159
160 double voteRatio()
161 {
162 ASSERT(find() == this);
163 return static_cast<double>(m_votes[1]) / m_votes[0];
164 }
165
166 bool shouldUseDoubleFormatAccordingToVote();
167
168 DoubleFormatState doubleFormatState()
169 {
170 return find()->m_doubleFormatState;
171 }
172
173 bool shouldUseDoubleFormat()
174 {
175 ASSERT(isRoot());
176 bool doubleState = m_doubleFormatState == UsingDoubleFormat;
177 ASSERT(!(doubleState && shouldNeverUnbox()));
178 return doubleState && isProfitableToUnbox();
179 }
180
181 bool tallyVotesForShouldUseDoubleFormat();
182
183 bool mergeDoubleFormatState(DoubleFormatState);
184
185 bool makePredictionForDoubleFormat();
186
187 NodeFlags flags() const { return m_flags; }
188
189 bool mergeFlags(NodeFlags newFlags)
190 {
191 return checkAndSet(m_flags, m_flags | newFlags);
192 }
193
194 FlushFormat flushFormat();
195
196 bool couldRepresentInt52();
197
198 FlushedAt flushedAt()
199 {
200 return FlushedAt(flushFormat(), machineLocal());
201 }
202
203private:
204 bool couldRepresentInt52Impl();
205
206 // This is slightly space-inefficient, since anything we're unified with
207 // will have the same operand and should have the same prediction. But
208 // putting them here simplifies the code, and we don't expect DFG space
209 // usage for variable access nodes do be significant.
210
211 VirtualRegister m_local;
212 VirtualRegister m_machineLocal;
213 SpeculatedType m_prediction;
214 SpeculatedType m_argumentAwarePrediction;
215 NodeFlags m_flags;
216
217 bool m_shouldNeverUnbox;
218 bool m_structureCheckHoistingFailed;
219 bool m_checkArrayHoistingFailed;
220 bool m_isProfitableToUnbox;
221 bool m_isLoadedFrom;
222
223 float m_votes[2]; // Used primarily for double voting but may be reused for other purposes.
224 DoubleFormatState m_doubleFormatState;
225};
226
227} } // namespace JSC::DFG
228
229#endif // ENABLE(DFG_JIT)
230