diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGVariableAccessData.h')
| -rw-r--r-- | Source/JavaScriptCore/dfg/DFGVariableAccessData.h | 207 |
1 files changed, 182 insertions, 25 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h index 0f817561c..5f83aeaf5 100644 --- a/Source/JavaScriptCore/dfg/DFGVariableAccessData.h +++ b/Source/JavaScriptCore/dfg/DFGVariableAccessData.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,8 +26,6 @@ #ifndef DFGVariableAccessData_h #define DFGVariableAccessData_h -#if ENABLE(DFG_JIT) - #include "DFGCommon.h" #include "DFGDoubleFormatState.h" #include "DFGFlushFormat.h" @@ -36,6 +34,7 @@ #include "Operands.h" #include "SpeculatedType.h" #include "VirtualRegister.h" +#include <wtf/Platform.h> #include <wtf/UnionFind.h> #include <wtf/Vector.h> @@ -47,8 +46,39 @@ enum DoubleBallot { VoteValue, VoteDouble }; class VariableAccessData : public UnionFind<VariableAccessData> { public: - VariableAccessData(); - VariableAccessData(VirtualRegister local); + VariableAccessData() + : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min())) + , m_prediction(SpecNone) + , m_argumentAwarePrediction(SpecNone) + , m_flags(0) + , m_isCaptured(false) + , m_shouldNeverUnbox(false) + , m_isArgumentsAlias(false) + , m_structureCheckHoistingFailed(false) + , m_checkArrayHoistingFailed(false) + , m_isProfitableToUnbox(false) + , m_isLoadedFrom(false) + , m_doubleFormatState(EmptyDoubleFormatState) + { + clearVotes(); + } + + VariableAccessData(VirtualRegister local, bool isCaptured) + : m_local(local) + , m_prediction(SpecNone) + , m_argumentAwarePrediction(SpecNone) + , m_flags(0) + , m_isCaptured(isCaptured) + , m_shouldNeverUnbox(isCaptured) + , m_isArgumentsAlias(false) + , m_structureCheckHoistingFailed(false) + , m_checkArrayHoistingFailed(false) + , m_isProfitableToUnbox(false) + , m_isLoadedFrom(false) + , m_doubleFormatState(EmptyDoubleFormatState) + { + clearVotes(); + } VirtualRegister local() { @@ -62,9 +92,20 @@ public: return m_machineLocal; } + bool mergeIsCaptured(bool isCaptured) + { + return checkAndSet(m_shouldNeverUnbox, m_shouldNeverUnbox | isCaptured) + | checkAndSet(m_isCaptured, m_isCaptured | isCaptured); + } + + bool isCaptured() + { + return m_isCaptured; + } + bool mergeIsProfitableToUnbox(bool isProfitableToUnbox) { - return checkAndSet(m_isProfitableToUnbox, m_isProfitableToUnbox || isProfitableToUnbox); + return checkAndSet(m_isProfitableToUnbox, m_isProfitableToUnbox | isProfitableToUnbox); } bool isProfitableToUnbox() @@ -72,13 +113,21 @@ public: return m_isProfitableToUnbox; } - bool mergeShouldNeverUnbox(bool shouldNeverUnbox); + bool mergeShouldNeverUnbox(bool shouldNeverUnbox) + { + bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox; + if (newShouldNeverUnbox == m_shouldNeverUnbox) + return false; + m_shouldNeverUnbox = newShouldNeverUnbox; + return true; + } // Returns true if it would be unsound to store the value in an unboxed fashion. // If this returns false, it simply means that it is sound to unbox; it doesn't // mean that we have actually done so. bool shouldNeverUnbox() { + ASSERT(!(m_isCaptured && !m_shouldNeverUnbox)); return m_shouldNeverUnbox; } @@ -92,12 +141,12 @@ public: bool mergeStructureCheckHoistingFailed(bool failed) { - return checkAndSet(m_structureCheckHoistingFailed, m_structureCheckHoistingFailed || failed); + return checkAndSet(m_structureCheckHoistingFailed, m_structureCheckHoistingFailed | failed); } bool mergeCheckArrayHoistingFailed(bool failed) { - return checkAndSet(m_checkArrayHoistingFailed, m_checkArrayHoistingFailed || failed); + return checkAndSet(m_checkArrayHoistingFailed, m_checkArrayHoistingFailed | failed); } bool structureCheckHoistingFailed() @@ -110,9 +159,19 @@ public: return m_checkArrayHoistingFailed; } + bool mergeIsArgumentsAlias(bool isArgumentsAlias) + { + return checkAndSet(m_isArgumentsAlias, m_isArgumentsAlias | isArgumentsAlias); + } + + bool isArgumentsAlias() + { + return m_isArgumentsAlias; + } + bool mergeIsLoadedFrom(bool isLoadedFrom) { - return checkAndSet(m_isLoadedFrom, m_isLoadedFrom || isLoadedFrom); + return checkAndSet(m_isLoadedFrom, m_isLoadedFrom | isLoadedFrom); } void setIsLoadedFrom(bool isLoadedFrom) @@ -125,7 +184,14 @@ public: return m_isLoadedFrom; } - bool predict(SpeculatedType prediction); + bool predict(SpeculatedType prediction) + { + VariableAccessData* self = find(); + bool result = mergeSpeculation(self->m_prediction, prediction); + if (result) + mergeSpeculation(m_argumentAwarePrediction, m_prediction); + return result; + } SpeculatedType nonUnifiedPrediction() { @@ -142,7 +208,10 @@ public: return find()->m_argumentAwarePrediction; } - bool mergeArgumentAwarePrediction(SpeculatedType prediction); + bool mergeArgumentAwarePrediction(SpeculatedType prediction) + { + return mergeSpeculation(find()->m_argumentAwarePrediction, prediction); + } void clearVotes() { @@ -151,10 +220,10 @@ public: m_votes[1] = 0; } - void vote(unsigned ballot, float weight = 1) + void vote(unsigned ballot) { ASSERT(ballot < 2); - m_votes[ballot] += weight; + m_votes[ballot]++; } double voteRatio() @@ -163,7 +232,39 @@ public: return static_cast<double>(m_votes[1]) / m_votes[0]; } - bool shouldUseDoubleFormatAccordingToVote(); + bool 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; + } DoubleFormatState doubleFormatState() { @@ -175,14 +276,47 @@ public: ASSERT(isRoot()); bool doubleState = m_doubleFormatState == UsingDoubleFormat; ASSERT(!(doubleState && shouldNeverUnbox())); + ASSERT(!(doubleState && isCaptured())); return doubleState && isProfitableToUnbox(); } - bool tallyVotesForShouldUseDoubleFormat(); + bool tallyVotesForShouldUseDoubleFormat() + { + ASSERT(isRoot()); + + if (local().isArgument() || shouldNeverUnbox()) + 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 mergeDoubleFormatState(DoubleFormatState); + bool mergeDoubleFormatState(DoubleFormatState doubleFormatState) + { + return DFG::mergeDoubleFormatState(find()->m_doubleFormatState, doubleFormatState); + } - bool makePredictionForDoubleFormat(); + bool makePredictionForDoubleFormat() + { + ASSERT(isRoot()); + + if (m_doubleFormatState != UsingDoubleFormat) + return false; + + return mergeSpeculation(m_prediction, SpecDouble); + } NodeFlags flags() const { return m_flags; } @@ -191,9 +325,34 @@ public: return checkAndSet(m_flags, m_flags | newFlags); } - FlushFormat flushFormat(); - - bool couldRepresentInt52(); + FlushFormat flushFormat() + { + ASSERT(find() == this); + + if (isArgumentsAlias()) + return FlushedArguments; + + if (!shouldUnboxIfPossible()) + return FlushedJSValue; + + if (shouldUseDoubleFormat()) + return FlushedDouble; + + SpeculatedType prediction = argumentAwarePrediction(); + if (isInt32Speculation(prediction)) + return FlushedInt32; + + if (enableInt52() && !m_local.isArgument() && isMachineIntSpeculation(prediction)) + return FlushedInt52; + + if (isCellSpeculation(prediction)) + return FlushedCell; + + if (isBooleanSpeculation(prediction)) + return FlushedBoolean; + + return FlushedJSValue; + } FlushedAt flushedAt() { @@ -201,8 +360,6 @@ public: } private: - bool couldRepresentInt52Impl(); - // This is slightly space-inefficient, since anything we're unified with // will have the same operand and should have the same prediction. But // putting them here simplifies the code, and we don't expect DFG space @@ -214,7 +371,9 @@ private: SpeculatedType m_argumentAwarePrediction; NodeFlags m_flags; + bool m_isCaptured; bool m_shouldNeverUnbox; + bool m_isArgumentsAlias; bool m_structureCheckHoistingFailed; bool m_checkArrayHoistingFailed; bool m_isProfitableToUnbox; @@ -226,6 +385,4 @@ private: } } // namespace JSC::DFG -#endif // ENABLE(DFG_JIT) - #endif // DFGVariableAccessData_h |
