1/*
2 * Copyright (C) 2014 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 "DFGVariableAccessData.h"
28
29#if ENABLE(DFG_JIT)
30
31namespace JSC { namespace DFG {
32
33VariableAccessData::VariableAccessData()
34    : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min()))
35    , m_prediction(SpecNone)
36    , m_argumentAwarePrediction(SpecNone)
37    , m_flags(0)
38    , m_isCaptured(false)
39    , m_shouldNeverUnbox(false)
40    , m_isArgumentsAlias(false)
41    , m_structureCheckHoistingFailed(false)
42    , m_checkArrayHoistingFailed(false)
43    , m_isProfitableToUnbox(false)
44    , m_isLoadedFrom(false)
45    , m_doubleFormatState(EmptyDoubleFormatState)
46{
47    clearVotes();
48}
49
50VariableAccessData::VariableAccessData(VirtualRegister local, bool isCaptured)
51    : m_local(local)
52    , m_prediction(SpecNone)
53    , m_argumentAwarePrediction(SpecNone)
54    , m_flags(0)
55    , m_isCaptured(isCaptured)
56    , m_shouldNeverUnbox(isCaptured)
57    , m_isArgumentsAlias(false)
58    , m_structureCheckHoistingFailed(false)
59    , m_checkArrayHoistingFailed(false)
60    , m_isProfitableToUnbox(false)
61    , m_isLoadedFrom(false)
62    , m_doubleFormatState(EmptyDoubleFormatState)
63{
64    clearVotes();
65}
66
67bool VariableAccessData::mergeIsCaptured(bool isCaptured)
68{
69    return checkAndSet(m_shouldNeverUnbox, m_shouldNeverUnbox | isCaptured)
70        | checkAndSet(m_isCaptured, m_isCaptured | isCaptured);
71}
72
73bool VariableAccessData::mergeShouldNeverUnbox(bool shouldNeverUnbox)
74{
75    bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox;
76    if (newShouldNeverUnbox == m_shouldNeverUnbox)
77        return false;
78    m_shouldNeverUnbox = newShouldNeverUnbox;
79    return true;
80}
81
82bool VariableAccessData::predict(SpeculatedType prediction)
83{
84    VariableAccessData* self = find();
85    bool result = mergeSpeculation(self->m_prediction, prediction);
86    if (result)
87        mergeSpeculation(m_argumentAwarePrediction, m_prediction);
88    return result;
89}
90
91bool VariableAccessData::mergeArgumentAwarePrediction(SpeculatedType prediction)
92{
93    return mergeSpeculation(find()->m_argumentAwarePrediction, prediction);
94}
95
96bool VariableAccessData::shouldUseDoubleFormatAccordingToVote()
97{
98    // We don't support this facility for arguments, yet.
99    // FIXME: make this work for arguments.
100    if (local().isArgument())
101        return false;
102
103    // If the variable is not a number prediction, then this doesn't
104    // make any sense.
105    if (!isFullNumberSpeculation(prediction())) {
106        // FIXME: we may end up forcing a local in inlined argument position to be a double even
107        // if it is sometimes not even numeric, since this never signals the fact that it doesn't
108        // want doubles. https://bugs.webkit.org/show_bug.cgi?id=109511
109        return false;
110    }
111
112    // If the variable is predicted to hold only doubles, then it's a
113    // no-brainer: it should be formatted as a double.
114    if (isDoubleSpeculation(prediction()))
115        return true;
116
117    // If the variable is known to be used as an integer, then be safe -
118    // don't force it to be a double.
119    if (flags() & NodeBytecodeUsesAsInt)
120        return false;
121
122    // If the variable has been voted to become a double, then make it a
123    // double.
124    if (voteRatio() >= Options::doubleVoteRatioForDoubleFormat())
125        return true;
126
127    return false;
128}
129
130bool VariableAccessData::tallyVotesForShouldUseDoubleFormat()
131{
132    ASSERT(isRoot());
133
134    if (local().isArgument() || shouldNeverUnbox()
135        || (flags() & NodeBytecodeUsesAsArrayIndex))
136        return DFG::mergeDoubleFormatState(m_doubleFormatState, NotUsingDoubleFormat);
137
138    if (m_doubleFormatState == CantUseDoubleFormat)
139        return false;
140
141    bool newValueOfShouldUseDoubleFormat = shouldUseDoubleFormatAccordingToVote();
142    if (!newValueOfShouldUseDoubleFormat) {
143        // We monotonically convert to double. Hence, if the fixpoint leads us to conclude that we should
144        // switch back to int, we instead ignore this and stick with double.
145        return false;
146    }
147
148    if (m_doubleFormatState == UsingDoubleFormat)
149        return false;
150
151    return DFG::mergeDoubleFormatState(m_doubleFormatState, UsingDoubleFormat);
152}
153
154bool VariableAccessData::mergeDoubleFormatState(DoubleFormatState doubleFormatState)
155{
156    return DFG::mergeDoubleFormatState(find()->m_doubleFormatState, doubleFormatState);
157}
158
159bool VariableAccessData::makePredictionForDoubleFormat()
160{
161    ASSERT(isRoot());
162
163    if (m_doubleFormatState != UsingDoubleFormat)
164        return false;
165
166    SpeculatedType type = m_prediction;
167    if (type & ~SpecBytecodeNumber)
168        type |= SpecDoublePureNaN;
169    if (type & SpecMachineInt)
170        type |= SpecInt52AsDouble;
171    return checkAndSet(m_prediction, type);
172}
173
174bool VariableAccessData::couldRepresentInt52()
175{
176    if (shouldNeverUnbox())
177        return false;
178
179    return couldRepresentInt52Impl();
180}
181
182bool VariableAccessData::couldRepresentInt52Impl()
183{
184    // The hardware has to support it.
185    if (!enableInt52())
186        return false;
187
188    // We punt for machine arguments.
189    if (m_local.isArgument())
190        return false;
191
192    // The argument-aware prediction -- which merges all of an (inlined or machine)
193    // argument's variable access datas' predictions -- must possibly be MachineInt.
194    return !(argumentAwarePrediction() & ~SpecMachineInt);
195}
196
197FlushFormat VariableAccessData::flushFormat()
198{
199    ASSERT(find() == this);
200
201    if (isArgumentsAlias())
202        return FlushedArguments;
203
204    if (!shouldUnboxIfPossible())
205        return FlushedJSValue;
206
207    if (shouldUseDoubleFormat())
208        return FlushedDouble;
209
210    SpeculatedType prediction = argumentAwarePrediction();
211
212    // This guard is here to protect the call to couldRepresentInt52(), which will return
213    // true for !prediction.
214    if (!prediction)
215        return FlushedJSValue;
216
217    if (isInt32Speculation(prediction))
218        return FlushedInt32;
219
220    if (couldRepresentInt52Impl())
221        return FlushedInt52;
222
223    if (isCellSpeculation(prediction))
224        return FlushedCell;
225
226    if (isBooleanSpeculation(prediction))
227        return FlushedBoolean;
228
229    return FlushedJSValue;
230}
231
232} } // namespace JSC::DFG
233
234#endif // ENABLE(DFG_JIT)
235
236