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