| /* |
| * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "DFGVariableAccessData.h" |
| |
| #if ENABLE(DFG_JIT) |
| |
| namespace JSC { namespace DFG { |
| |
| VariableAccessData::VariableAccessData() |
| : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min())) |
| , m_prediction(SpecNone) |
| , m_argumentAwarePrediction(SpecNone) |
| , m_flags(0) |
| , m_shouldNeverUnbox(false) |
| , m_structureCheckHoistingFailed(false) |
| , m_checkArrayHoistingFailed(false) |
| , m_isProfitableToUnbox(false) |
| , m_isLoadedFrom(false) |
| , m_doubleFormatState(EmptyDoubleFormatState) |
| { |
| clearVotes(); |
| } |
| |
| VariableAccessData::VariableAccessData(VirtualRegister local) |
| : m_local(local) |
| , m_prediction(SpecNone) |
| , m_argumentAwarePrediction(SpecNone) |
| , m_flags(0) |
| , m_shouldNeverUnbox(false) |
| , m_structureCheckHoistingFailed(false) |
| , m_checkArrayHoistingFailed(false) |
| , m_isProfitableToUnbox(false) |
| , m_isLoadedFrom(false) |
| , m_doubleFormatState(EmptyDoubleFormatState) |
| { |
| clearVotes(); |
| } |
| |
| bool VariableAccessData::mergeShouldNeverUnbox(bool shouldNeverUnbox) |
| { |
| bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox; |
| if (newShouldNeverUnbox == m_shouldNeverUnbox) |
| return false; |
| m_shouldNeverUnbox = newShouldNeverUnbox; |
| return true; |
| } |
| |
| bool VariableAccessData::predict(SpeculatedType prediction) |
| { |
| VariableAccessData* self = find(); |
| bool result = mergeSpeculation(self->m_prediction, prediction); |
| if (result) |
| mergeSpeculation(m_argumentAwarePrediction, m_prediction); |
| return result; |
| } |
| |
| bool VariableAccessData::mergeArgumentAwarePrediction(SpeculatedType prediction) |
| { |
| return mergeSpeculation(find()->m_argumentAwarePrediction, prediction); |
| } |
| |
| bool VariableAccessData::shouldUseDoubleFormatAccordingToVote() |
| { |
| // We don't support this facility for arguments, yet. |
| // FIXME: make this work for arguments. |
| if (local().isArgument()) |
| return false; |
| |
| // If the variable is not a number prediction, then this doesn't |
| // make any sense. |
| if (!isFullNumberSpeculation(prediction())) { |
| // FIXME: we may end up forcing a local in inlined argument position to be a double even |
| // if it is sometimes not even numeric, since this never signals the fact that it doesn't |
| // want doubles. https://bugs.webkit.org/show_bug.cgi?id=109511 |
| return false; |
| } |
| |
| // If the variable is predicted to hold only doubles, then it's a |
| // no-brainer: it should be formatted as a double. |
| if (isDoubleSpeculation(prediction())) |
| return true; |
| |
| // If the variable is known to be used as an integer, then be safe - |
| // don't force it to be a double. |
| if (flags() & NodeBytecodeUsesAsInt) |
| return false; |
| |
| // If the variable has been voted to become a double, then make it a |
| // double. |
| if (voteRatio() >= Options::doubleVoteRatioForDoubleFormat()) |
| return true; |
| |
| return false; |
| } |
| |
| bool VariableAccessData::tallyVotesForShouldUseDoubleFormat() |
| { |
| ASSERT(isRoot()); |
| |
| if (local().isArgument() || shouldNeverUnbox() |
| || (flags() & NodeBytecodeUsesAsArrayIndex)) |
| return DFG::mergeDoubleFormatState(m_doubleFormatState, NotUsingDoubleFormat); |
| |
| if (m_doubleFormatState == CantUseDoubleFormat) |
| return false; |
| |
| bool newValueOfShouldUseDoubleFormat = shouldUseDoubleFormatAccordingToVote(); |
| if (!newValueOfShouldUseDoubleFormat) { |
| // We monotonically convert to double. Hence, if the fixpoint leads us to conclude that we should |
| // switch back to int, we instead ignore this and stick with double. |
| return false; |
| } |
| |
| if (m_doubleFormatState == UsingDoubleFormat) |
| return false; |
| |
| return DFG::mergeDoubleFormatState(m_doubleFormatState, UsingDoubleFormat); |
| } |
| |
| bool VariableAccessData::mergeDoubleFormatState(DoubleFormatState doubleFormatState) |
| { |
| return DFG::mergeDoubleFormatState(find()->m_doubleFormatState, doubleFormatState); |
| } |
| |
| bool VariableAccessData::makePredictionForDoubleFormat() |
| { |
| ASSERT(isRoot()); |
| |
| if (m_doubleFormatState != UsingDoubleFormat) |
| return false; |
| |
| SpeculatedType type = m_prediction; |
| if (type & ~SpecBytecodeNumber) |
| type |= SpecDoublePureNaN; |
| if (type & SpecAnyInt) |
| type |= SpecAnyIntAsDouble; |
| return checkAndSet(m_prediction, type); |
| } |
| |
| bool VariableAccessData::couldRepresentInt52() |
| { |
| if (shouldNeverUnbox()) |
| return false; |
| |
| return couldRepresentInt52Impl(); |
| } |
| |
| bool VariableAccessData::couldRepresentInt52Impl() |
| { |
| // The hardware has to support it. |
| if (!enableInt52()) |
| return false; |
| |
| // We punt for machine arguments. |
| if (m_local.isArgument()) |
| return false; |
| |
| // The argument-aware prediction -- which merges all of an (inlined or machine) |
| // argument's variable access datas' predictions -- must possibly be AnyInt. |
| return !(argumentAwarePrediction() & ~SpecAnyInt); |
| } |
| |
| FlushFormat VariableAccessData::flushFormat() |
| { |
| ASSERT(find() == this); |
| |
| if (!shouldUnboxIfPossible()) |
| return FlushedJSValue; |
| |
| if (shouldUseDoubleFormat()) |
| return FlushedDouble; |
| |
| SpeculatedType prediction = argumentAwarePrediction(); |
| |
| // This guard is here to protect the call to couldRepresentInt52(), which will return |
| // true for !prediction. |
| if (!prediction) |
| return FlushedJSValue; |
| |
| if (isInt32Speculation(prediction)) |
| return FlushedInt32; |
| |
| if (couldRepresentInt52Impl()) |
| return FlushedInt52; |
| |
| if (isCellSpeculation(prediction)) |
| return FlushedCell; |
| |
| if (isBooleanSpeculation(prediction)) |
| return FlushedBoolean; |
| |
| return FlushedJSValue; |
| } |
| |
| } } // namespace JSC::DFG |
| |
| #endif // ENABLE(DFG_JIT) |
| |