/*
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013, 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 DFGAbstractValue_h
#define DFGAbstractValue_h
-#include <wtf/Platform.h>
-
#if ENABLE(DFG_JIT)
#include "ArrayProfile.h"
+#include "DFGFiltrationResult.h"
+#include "DFGNodeFlags.h"
#include "DFGStructureAbstractValue.h"
#include "JSCell.h"
#include "SpeculatedType.h"
+#include "DumpContext.h"
#include "StructureSet.h"
namespace JSC { namespace DFG {
+class Graph;
+struct Node;
+
struct AbstractValue {
AbstractValue()
: m_type(SpecNone)
checkConsistency();
}
- bool isClear() const
+ bool isClear() const { return m_type == SpecNone; }
+ bool operator!() const { return isClear(); }
+
+ void makeHeapTop()
{
- bool result = m_type == SpecNone && !m_arrayModes && m_currentKnownStructure.isClear() && m_futurePossibleStructure.isClear();
- if (result)
- ASSERT(!m_value);
- return result;
+ makeTop(SpecHeapTop);
}
- void makeTop()
+ void makeBytecodeTop()
{
- m_type |= SpecTop; // The state may have included SpecEmpty, in which case we want this to become SpecEmptyOrTop.
- m_arrayModes = ALL_ARRAY_MODES;
- m_currentKnownStructure.makeTop();
- m_futurePossibleStructure.makeTop();
- m_value = JSValue();
- checkConsistency();
+ makeTop(SpecBytecodeTop);
}
void clobberStructures()
m_value = JSValue();
}
- bool isTop() const
+ bool isHeapTop() const
{
- return m_type == SpecTop && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop();
+ return (m_type | SpecHeapTop) == m_type && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop();
}
bool valueIsTop() const
return m_value;
}
- static AbstractValue top()
+ static AbstractValue heapTop()
{
AbstractValue result;
- result.makeTop();
+ result.makeHeapTop();
return result;
}
- void setMostSpecific(JSValue value)
- {
- if (!!value && value.isCell()) {
- Structure* structure = value.asCell()->structure();
- m_currentKnownStructure = structure;
- setFuturePossibleStructure(structure);
- m_arrayModes = asArrayModes(structure->indexingType());
- } else {
- m_currentKnownStructure.clear();
- m_futurePossibleStructure.clear();
- m_arrayModes = 0;
- }
-
- m_type = speculationFromValue(value);
- m_value = value;
-
- checkConsistency();
- }
-
- void set(JSValue value)
- {
- if (!!value && value.isCell()) {
- m_currentKnownStructure.makeTop();
- Structure* structure = value.asCell()->structure();
- setFuturePossibleStructure(structure);
- m_arrayModes = asArrayModes(structure->indexingType());
- clobberArrayModes();
- } else {
- m_currentKnownStructure.clear();
- m_futurePossibleStructure.clear();
- m_arrayModes = 0;
- }
-
- m_type = speculationFromValue(value);
- m_value = value;
-
- checkConsistency();
- }
-
- void set(Structure* structure)
- {
- m_currentKnownStructure = structure;
- setFuturePossibleStructure(structure);
- m_arrayModes = asArrayModes(structure->indexingType());
- m_type = speculationFromStructure(structure);
- m_value = JSValue();
-
- checkConsistency();
- }
+ void setMostSpecific(Graph&, JSValue);
+ void set(Graph&, JSValue);
+ void set(Graph&, Structure*);
- void set(SpeculatedType type)
+ void setType(SpeculatedType type)
{
if (type & SpecCell) {
m_currentKnownStructure.makeTop();
checkConsistency();
}
+ void fixTypeForRepresentation(NodeFlags representation);
+ void fixTypeForRepresentation(Node*);
+
bool operator==(const AbstractValue& other) const
{
return m_type == other.m_type
checkConsistency();
}
- void filter(const StructureSet& other)
+ bool couldBeType(SpeculatedType desiredType)
{
- // FIXME: This could be optimized for the common case of m_type not
- // having structures, array modes, or a specific value.
- // https://bugs.webkit.org/show_bug.cgi?id=109663
- m_type &= other.speculationFromStructures();
- m_arrayModes &= other.arrayModesFromStructures();
- m_currentKnownStructure.filter(other);
- if (m_currentKnownStructure.isClear())
- m_futurePossibleStructure.clear();
- else if (m_currentKnownStructure.hasSingleton())
- filterFuturePossibleStructure(m_currentKnownStructure.singleton());
-
- // It's possible that prior to the above two statements we had (Foo, TOP), where
- // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that
- // case, we will now have (None, [someStructure]). In general, we need to make
- // sure that new information gleaned from the SpeculatedType needs to be fed back
- // into the information gleaned from the StructureSet.
- m_currentKnownStructure.filter(m_type);
- m_futurePossibleStructure.filter(m_type);
-
- filterArrayModesByType();
- filterValueByType();
-
- checkConsistency();
+ return !!(m_type & desiredType);
}
- void filterArrayModes(ArrayModes arrayModes)
+ bool isType(SpeculatedType desiredType)
{
- ASSERT(arrayModes);
-
- m_type &= SpecCell;
- m_arrayModes &= arrayModes;
-
- // I could do more fancy filtering here. But it probably won't make any difference.
-
- checkConsistency();
+ return !(m_type & ~desiredType);
}
- void filter(SpeculatedType type)
- {
- if (type == SpecTop)
- return;
- m_type &= type;
-
- // It's possible that prior to this filter() call we had, say, (Final, TOP), and
- // the passed type is Array. At this point we'll have (None, TOP). The best way
- // to ensure that the structure filtering does the right thing is to filter on
- // the new type (None) rather than the one passed (Array).
- m_currentKnownStructure.filter(m_type);
- m_futurePossibleStructure.filter(m_type);
-
- filterArrayModesByType();
- filterValueByType();
-
- checkConsistency();
- }
+ FiltrationResult filter(Graph&, const StructureSet&);
- void filterByValue(JSValue value)
- {
- filter(speculationFromValue(value));
- if (m_type)
- m_value = value;
- }
+ FiltrationResult filterArrayModes(ArrayModes);
- bool validateType(JSValue value) const
- {
- if (isTop())
- return true;
-
- if (mergeSpeculations(m_type, speculationFromValue(value)) != m_type)
- return false;
-
- if (value.isEmpty()) {
- ASSERT(m_type & SpecEmpty);
- return true;
- }
-
- return true;
- }
+ FiltrationResult filter(SpeculatedType);
+
+ FiltrationResult filterByValue(JSValue);
bool validate(JSValue value) const
{
- if (isTop())
+ if (isHeapTop())
return true;
if (!!m_value && m_value != value)
return 0;
}
- void checkConsistency() const
+ bool hasClobberableState() const
{
- if (!(m_type & SpecCell)) {
- ASSERT(m_currentKnownStructure.isClear());
- ASSERT(m_futurePossibleStructure.isClear());
- ASSERT(!m_arrayModes);
- }
-
- if (isClear())
- ASSERT(!m_value);
-
- if (!!m_value)
- ASSERT(mergeSpeculations(m_type, speculationFromValue(m_value)) == m_type);
-
- // Note that it's possible for a prediction like (Final, []). This really means that
- // the value is bottom and that any code that uses the value is unreachable. But
- // we don't want to get pedantic about this as it would only increase the computational
- // complexity of the code.
+ return m_currentKnownStructure.isNeitherClearNorTop()
+ || !arrayModesAreClearOrTop(m_arrayModes);
}
- void dump(PrintStream& out) const
- {
- out.print(
- "(", SpeculationDump(m_type), ", ", ArrayModesDump(m_arrayModes), ", ",
- m_currentKnownStructure, ", ", m_futurePossibleStructure);
- if (!!m_value)
- out.print(", ", m_value);
- out.print(")");
- }
+#if ASSERT_DISABLED
+ void checkConsistency() const { }
+#else
+ void checkConsistency() const;
+#endif
+
+ void dumpInContext(PrintStream&, DumpContext*) const;
+ void dump(PrintStream&) const;
// A great way to think about the difference between m_currentKnownStructure and
// m_futurePossibleStructure is to consider these four examples:
// y = x.f;
//
// Where x will later have a new property added to it, 'g'. Because of the
- // known but not-yet-executed property addition, x's currently structure will
+ // known but not-yet-executed property addition, x's current structure will
// not be watchpointable; hence we have no way of statically bounding the set
// of possible structures that x may have if a clobbering event happens. So,
// x's m_currentKnownStructure will be whatever structure we check to get
m_arrayModes = ALL_ARRAY_MODES;
}
- void setFuturePossibleStructure(Structure* structure)
+ bool validateType(JSValue value) const
{
- if (structure->transitionWatchpointSetIsStillValid())
- m_futurePossibleStructure = structure;
- else
- m_futurePossibleStructure.makeTop();
+ if (isHeapTop())
+ return true;
+
+ // Constant folding always represents Int52's in a double (i.e. Int52AsDouble).
+ // So speculationFromValue(value) for an Int52 value will return Int52AsDouble,
+ // and that's fine - the type validates just fine.
+ SpeculatedType type = m_type;
+ if (type & SpecInt52)
+ type |= SpecInt52AsDouble;
+
+ if (mergeSpeculations(type, speculationFromValue(value)) != type)
+ return false;
+
+ if (value.isEmpty()) {
+ ASSERT(m_type & SpecEmpty);
+ return true;
+ }
+
+ return true;
}
- void filterFuturePossibleStructure(Structure* structure)
+ void makeTop(SpeculatedType top)
{
- if (structure->transitionWatchpointSetIsStillValid())
- m_futurePossibleStructure.filter(StructureAbstractValue(structure));
- }
-
- // We could go further, and ensure that if the futurePossibleStructure contravenes
- // the value, then we could clear both of those things. But that's unlikely to help
- // in any realistic scenario, so we don't do it. Simpler is better.
- void filterValueByType()
- {
- if (!!m_type) {
- // The type is still non-empty. This implies that regardless of what filtering
- // was done, we either didn't have a value to begin with, or that value is still
- // valid.
- ASSERT(!m_value || validateType(m_value));
- return;
- }
-
- // The type has been rendered empty. That means that the value must now be invalid,
- // as well.
- ASSERT(!m_value || !validateType(m_value));
+ m_type |= top;
+ m_arrayModes = ALL_ARRAY_MODES;
+ m_currentKnownStructure.makeTop();
+ m_futurePossibleStructure.makeTop();
m_value = JSValue();
+ checkConsistency();
}
- void filterArrayModesByType()
- {
- if (!(m_type & SpecCell))
- m_arrayModes = 0;
- else if (!(m_type & ~SpecArray))
- m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
+ void setFuturePossibleStructure(Graph&, Structure*);
- // NOTE: If m_type doesn't have SpecArray set, that doesn't mean that the
- // array modes have to be a subset of ALL_NON_ARRAY_ARRAY_MODES, since
- // in the speculated type type-system, RegExpMatchesArry and ArrayPrototype
- // are Otherobj (since they are not *exactly* JSArray) but in the ArrayModes
- // type system they are arrays (since they expose the magical length
- // property and are otherwise allocated using array allocation). Hence the
- // following would be wrong:
- //
- // if (!(m_type & SpecArray))
- // m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
- }
+ void filterValueByType();
+ void filterArrayModesByType();
+
+ bool shouldBeClear() const;
+ FiltrationResult normalizeClarity();
};
} } // namespace JSC::DFG