/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#ifndef DFGVariableAccessData_h
#define DFGVariableAccessData_h
+#if ENABLE(DFG_JIT)
+
+#include "DFGCommon.h"
#include "DFGDoubleFormatState.h"
+#include "DFGFlushFormat.h"
+#include "DFGFlushedAt.h"
#include "DFGNodeFlags.h"
#include "Operands.h"
-#include "PredictedType.h"
+#include "SpeculatedType.h"
#include "VirtualRegister.h"
-#include <wtf/Platform.h>
#include <wtf/UnionFind.h>
#include <wtf/Vector.h>
namespace JSC { namespace DFG {
+struct Node;
+
+enum DoubleBallot { VoteValue, VoteDouble };
+
class VariableAccessData : public UnionFind<VariableAccessData> {
public:
- enum Ballot { VoteValue, VoteDouble };
+ VariableAccessData();
+ VariableAccessData(VirtualRegister local, bool isCaptured);
+
+ VirtualRegister local()
+ {
+ ASSERT(m_local == find()->m_local);
+ return m_local;
+ }
+
+ VirtualRegister& machineLocal()
+ {
+ ASSERT(find() == this);
+ return m_machineLocal;
+ }
- VariableAccessData()
- : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min()))
- , m_prediction(PredictNone)
- , m_argumentAwarePrediction(PredictNone)
- , m_flags(0)
- , m_doubleFormatState(EmptyDoubleFormatState)
+ bool mergeIsCaptured(bool isCaptured);
+
+ bool isCaptured()
{
- clearVotes();
+ return m_isCaptured;
}
- VariableAccessData(VirtualRegister local)
- : m_local(local)
- , m_prediction(PredictNone)
- , m_argumentAwarePrediction(PredictNone)
- , m_flags(0)
- , m_doubleFormatState(EmptyDoubleFormatState)
+ bool mergeIsProfitableToUnbox(bool isProfitableToUnbox)
{
- clearVotes();
+ return checkAndSet(m_isProfitableToUnbox, m_isProfitableToUnbox | isProfitableToUnbox);
}
- VirtualRegister local()
+ bool isProfitableToUnbox()
{
- ASSERT(m_local == find()->m_local);
- return m_local;
+ return m_isProfitableToUnbox;
}
- int operand()
+ bool mergeShouldNeverUnbox(bool shouldNeverUnbox);
+
+ // 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()
{
- return static_cast<int>(local());
+ ASSERT(!(m_isCaptured && !m_shouldNeverUnbox));
+ return m_shouldNeverUnbox;
}
- bool predict(PredictedType prediction)
+ // Returns true if we should be unboxing the value provided that the predictions
+ // and double format vote say so. This may return false even if shouldNeverUnbox()
+ // returns false, since this incorporates heuristics of profitability.
+ bool shouldUnboxIfPossible()
{
- VariableAccessData* self = find();
- bool result = mergePrediction(self->m_prediction, prediction);
- if (result)
- mergePrediction(m_argumentAwarePrediction, m_prediction);
- return result;
+ return !shouldNeverUnbox() && isProfitableToUnbox();
+ }
+
+ bool mergeStructureCheckHoistingFailed(bool failed)
+ {
+ return checkAndSet(m_structureCheckHoistingFailed, m_structureCheckHoistingFailed | failed);
}
- PredictedType nonUnifiedPrediction()
+ bool mergeCheckArrayHoistingFailed(bool failed)
+ {
+ return checkAndSet(m_checkArrayHoistingFailed, m_checkArrayHoistingFailed | failed);
+ }
+
+ bool structureCheckHoistingFailed()
+ {
+ return m_structureCheckHoistingFailed;
+ }
+
+ bool checkArrayHoistingFailed()
+ {
+ 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);
+ }
+
+ void setIsLoadedFrom(bool isLoadedFrom)
+ {
+ m_isLoadedFrom = isLoadedFrom;
+ }
+
+ bool isLoadedFrom()
+ {
+ return m_isLoadedFrom;
+ }
+
+ bool predict(SpeculatedType prediction);
+
+ SpeculatedType nonUnifiedPrediction()
{
return m_prediction;
}
- PredictedType prediction()
+ SpeculatedType prediction()
{
return find()->m_prediction;
}
- PredictedType argumentAwarePrediction()
+ SpeculatedType argumentAwarePrediction()
{
return find()->m_argumentAwarePrediction;
}
- bool mergeArgumentAwarePrediction(PredictedType prediction)
- {
- return mergePrediction(find()->m_argumentAwarePrediction, prediction);
- }
+ bool mergeArgumentAwarePrediction(SpeculatedType prediction);
void clearVotes()
{
ASSERT(find() == this);
- m_votes[VoteValue] = 0;
- m_votes[VoteDouble] = 0;
+ m_votes[0] = 0;
+ m_votes[1] = 0;
}
- void vote(Ballot ballot)
+ void vote(unsigned ballot, float weight = 1)
{
- ASSERT(static_cast<unsigned>(ballot) < 2);
- m_votes[ballot]++;
+ ASSERT(ballot < 2);
+ m_votes[ballot] += weight;
}
- double doubleVoteRatio()
+ double voteRatio()
{
ASSERT(find() == this);
- return static_cast<double>(m_votes[VoteDouble]) / m_votes[VoteValue];
- }
-
- bool shouldUseDoubleFormatAccordingToVote()
- {
- // We don't support this facility for arguments, yet.
- // FIXME: make this work for arguments.
- if (operandIsArgument(operand()))
- return false;
-
- // If the variable is not a number prediction, then this doesn't
- // make any sense.
- if (!isNumberPrediction(prediction()))
- 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 (isDoublePrediction(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() & NodeUsedAsInt)
- return false;
-
- // If the variable has been voted to become a double, then make it a
- // double.
- if (doubleVoteRatio() >= Options::doubleVoteRatioForDoubleFormat)
- return true;
-
- return false;
+ return static_cast<double>(m_votes[1]) / m_votes[0];
}
+ bool shouldUseDoubleFormatAccordingToVote();
+
DoubleFormatState doubleFormatState()
{
return find()->m_doubleFormatState;
bool shouldUseDoubleFormat()
{
ASSERT(isRoot());
- return m_doubleFormatState == UsingDoubleFormat;
+ bool doubleState = m_doubleFormatState == UsingDoubleFormat;
+ ASSERT(!(doubleState && shouldNeverUnbox()));
+ ASSERT(!(doubleState && isCaptured()));
+ return doubleState && isProfitableToUnbox();
}
- bool tallyVotesForShouldUseDoubleFormat()
- {
- ASSERT(isRoot());
-
- 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 tallyVotesForShouldUseDoubleFormat();
- bool mergeDoubleFormatState(DoubleFormatState doubleFormatState)
- {
- return DFG::mergeDoubleFormatState(find()->m_doubleFormatState, doubleFormatState);
- }
+ bool mergeDoubleFormatState(DoubleFormatState);
- bool makePredictionForDoubleFormat()
- {
- ASSERT(isRoot());
-
- if (m_doubleFormatState != UsingDoubleFormat)
- return false;
-
- return mergePrediction(m_prediction, PredictDouble);
- }
+ bool makePredictionForDoubleFormat();
NodeFlags flags() const { return m_flags; }
bool mergeFlags(NodeFlags newFlags)
{
- newFlags |= m_flags;
- if (newFlags == m_flags)
- return false;
- m_flags = newFlags;
- return true;
+ return checkAndSet(m_flags, m_flags | newFlags);
}
+ FlushFormat flushFormat();
+
+ bool couldRepresentInt52();
+
+ FlushedAt flushedAt()
+ {
+ return FlushedAt(flushFormat(), machineLocal());
+ }
+
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
// usage for variable access nodes do be significant.
VirtualRegister m_local;
- PredictedType m_prediction;
- PredictedType m_argumentAwarePrediction;
+ VirtualRegister m_machineLocal;
+ SpeculatedType m_prediction;
+ SpeculatedType m_argumentAwarePrediction;
NodeFlags m_flags;
-
- float m_votes[2];
+
+ bool m_isCaptured;
+ bool m_shouldNeverUnbox;
+ bool m_isArgumentsAlias;
+ bool m_structureCheckHoistingFailed;
+ bool m_checkArrayHoistingFailed;
+ bool m_isProfitableToUnbox;
+ bool m_isLoadedFrom;
+
+ float m_votes[2]; // Used primarily for double voting but may be reused for other purposes.
DoubleFormatState m_doubleFormatState;
};
} } // namespace JSC::DFG
+#endif // ENABLE(DFG_JIT)
+
#endif // DFGVariableAccessData_h