DFGAbstractValue.h [plain text]
#pragma once
#if ENABLE(DFG_JIT)
#include "ArrayProfile.h"
#include "DFGFiltrationResult.h"
#include "DFGFrozenValue.h"
#include "DFGNodeFlags.h"
#include "DFGStructureAbstractValue.h"
#include "DFGStructureClobberState.h"
#include "InferredType.h"
#include "JSCell.h"
#include "ResultType.h"
#include "SpeculatedType.h"
#include "DumpContext.h"
namespace JSC {
class TrackedReferences;
namespace DFG {
class Graph;
struct Node;
struct AbstractValue {
AbstractValue()
: m_type(SpecNone)
, m_arrayModes(0)
{
#if USE(JSVALUE64) && !defined(NDEBUG)
static bool needsDefaultConstructorCheck = true;
if (needsDefaultConstructorCheck) {
needsDefaultConstructorCheck = false;
ensureCanInitializeWithZeros();
}
#endif
}
void clear()
{
m_type = SpecNone;
m_arrayModes = 0;
m_structure.clear();
m_value = JSValue();
checkConsistency();
}
bool isClear() const { return m_type == SpecNone; }
bool operator!() const { return isClear(); }
void makeHeapTop()
{
makeTop(SpecHeapTop);
}
void makeBytecodeTop()
{
makeTop(SpecBytecodeTop);
}
void makeFullTop()
{
makeTop(SpecFullTop);
}
void clobberStructures()
{
if (m_type & SpecCell) {
m_structure.clobber();
clobberArrayModes();
} else {
ASSERT(m_structure.isClear());
ASSERT(!m_arrayModes);
}
checkConsistency();
}
static void clobberStructuresFor(AbstractValue& value)
{
value.clobberStructures();
}
void observeInvalidationPoint()
{
m_structure.observeInvalidationPoint();
checkConsistency();
}
static void observeInvalidationPointFor(AbstractValue& value)
{
value.observeInvalidationPoint();
}
void observeTransition(RegisteredStructure from, RegisteredStructure to)
{
if (m_type & SpecCell) {
m_structure.observeTransition(from, to);
observeIndexingTypeTransition(from->indexingType(), to->indexingType());
}
checkConsistency();
}
void observeTransitions(const TransitionVector& vector);
class TransitionObserver {
public:
TransitionObserver(RegisteredStructure from, RegisteredStructure to)
: m_from(from)
, m_to(to)
{
}
void operator()(AbstractValue& value)
{
value.observeTransition(m_from, m_to);
}
private:
RegisteredStructure m_from;
RegisteredStructure m_to;
};
class TransitionsObserver {
public:
TransitionsObserver(const TransitionVector& vector)
: m_vector(vector)
{
}
void operator()(AbstractValue& value)
{
value.observeTransitions(m_vector);
}
private:
const TransitionVector& m_vector;
};
void clobberValue()
{
m_value = JSValue();
}
bool isHeapTop() const
{
return (m_type | SpecHeapTop) == m_type
&& m_structure.isTop()
&& m_arrayModes == ALL_ARRAY_MODES
&& !m_value;
}
bool valueIsTop() const
{
return !m_value && m_type;
}
JSValue value() const
{
return m_value;
}
static AbstractValue heapTop()
{
AbstractValue result;
result.makeHeapTop();
return result;
}
static AbstractValue bytecodeTop()
{
AbstractValue result;
result.makeBytecodeTop();
return result;
}
static AbstractValue fullTop()
{
AbstractValue result;
result.makeFullTop();
return result;
}
void set(Graph&, const FrozenValue&, StructureClobberState);
void set(Graph&, Structure*);
void set(Graph&, RegisteredStructure);
void set(Graph&, const RegisteredStructureSet&);
void setType(Graph&, SpeculatedType);
void setType(SpeculatedType type)
{
RELEASE_ASSERT(!(type & SpecCell));
m_structure.clear();
m_arrayModes = 0;
m_type = type;
m_value = JSValue();
checkConsistency();
}
void set(Graph&, const InferredType::Descriptor&);
void set(Graph&, const InferredType::Descriptor&, StructureClobberState);
void fixTypeForRepresentation(Graph&, NodeFlags representation, Node* = nullptr);
void fixTypeForRepresentation(Graph&, Node*);
bool operator==(const AbstractValue& other) const
{
return m_type == other.m_type
&& m_arrayModes == other.m_arrayModes
&& m_structure == other.m_structure
&& m_value == other.m_value;
}
bool operator!=(const AbstractValue& other) const
{
return !(*this == other);
}
bool merge(const AbstractValue& other)
{
if (other.isClear())
return false;
#if !ASSERT_DISABLED
AbstractValue oldMe = *this;
#endif
bool result = false;
if (isClear()) {
*this = other;
result = !other.isClear();
} else {
result |= mergeSpeculation(m_type, other.m_type);
result |= mergeArrayModes(m_arrayModes, other.m_arrayModes);
result |= m_structure.merge(other.m_structure);
if (m_value != other.m_value) {
result |= !!m_value;
m_value = JSValue();
}
}
checkConsistency();
ASSERT(result == (*this != oldMe));
return result;
}
bool mergeOSREntryValue(Graph&, JSValue);
void merge(SpeculatedType type)
{
mergeSpeculation(m_type, type);
if (type & SpecCell) {
m_structure.makeTop();
m_arrayModes = ALL_ARRAY_MODES;
}
m_value = JSValue();
checkConsistency();
}
bool couldBeType(SpeculatedType desiredType) const
{
return !!(m_type & desiredType);
}
bool isType(SpeculatedType desiredType) const
{
return !(m_type & ~desiredType);
}
bool isType(Graph&, const InferredType::Descriptor&) const;
FiltrationResult filter(Graph&, const RegisteredStructureSet&, SpeculatedType admittedTypes = SpecNone);
FiltrationResult filterArrayModes(ArrayModes);
FiltrationResult filter(SpeculatedType);
FiltrationResult filterByValue(const FrozenValue& value);
FiltrationResult filter(const AbstractValue&);
FiltrationResult filterClassInfo(Graph&, const ClassInfo*);
FiltrationResult filter(Graph&, const InferredType::Descriptor&);
FiltrationResult changeStructure(Graph&, const RegisteredStructureSet&);
bool contains(RegisteredStructure) const;
bool validate(JSValue value) const
{
if (isHeapTop())
return true;
if (!!m_value && m_value != value)
return false;
if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type)
return false;
if (value.isEmpty()) {
ASSERT(m_type & SpecEmpty);
return true;
}
if (!!value && value.isCell()) {
ASSERT(m_type & SpecCell);
Structure* structure = value.asCell()->structure();
return m_structure.contains(structure)
&& (m_arrayModes & asArrayModes(structure->indexingType()));
}
return true;
}
bool hasClobberableState() const
{
return m_structure.isNeitherClearNorTop()
|| !arrayModesAreClearOrTop(m_arrayModes);
}
#if ASSERT_DISABLED
void checkConsistency() const { }
void assertIsRegistered(Graph&) const { }
#else
void checkConsistency() const;
void assertIsRegistered(Graph&) const;
#endif
ResultType resultType() const;
void dumpInContext(PrintStream&, DumpContext*) const;
void dump(PrintStream&) const;
void validateReferences(const TrackedReferences&);
StructureAbstractValue m_structure;
SpeculatedType m_type;
ArrayModes m_arrayModes;
JSValue m_value;
private:
void clobberArrayModes()
{
m_arrayModes = ALL_ARRAY_MODES;
}
void observeIndexingTypeTransition(IndexingType from, IndexingType to)
{
if (m_arrayModes & asArrayModes(from))
m_arrayModes |= asArrayModes(to);
}
bool validateType(JSValue value) const
{
if (isHeapTop())
return true;
SpeculatedType type = m_type;
if (type & SpecInt52Only)
type |= SpecAnyIntAsDouble;
if (mergeSpeculations(type, speculationFromValue(value)) != type)
return false;
if (value.isEmpty()) {
ASSERT(m_type & SpecEmpty);
return true;
}
return true;
}
void makeTop(SpeculatedType top)
{
m_type |= top;
m_arrayModes = ALL_ARRAY_MODES;
m_structure.makeTop();
m_value = JSValue();
checkConsistency();
}
void filterValueByType();
void filterArrayModesByType();
#if USE(JSVALUE64) && !defined(NDEBUG)
void ensureCanInitializeWithZeros();
#endif
bool shouldBeClear() const;
FiltrationResult normalizeClarity();
FiltrationResult normalizeClarity(Graph&);
};
} }
#if USE(JSVALUE64)
namespace WTF {
template <>
struct VectorTraits<JSC::DFG::AbstractValue> : VectorTraitsBase<false, JSC::DFG::AbstractValue> {
static const bool canInitializeWithMemset = true;
};
template <>
struct HashTraits<JSC::DFG::AbstractValue> : GenericHashTraits<JSC::DFG::AbstractValue> {
static const bool emptyValueIsZero = true;
};
};
#endif // USE(JSVALUE64)
#endif // ENABLE(DFG_JIT)